summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2013-08-26 08:15:55 -0400
committerAnas Nashif <anas.nashif@intel.com>2013-08-26 08:15:55 -0400
commitbb4dd8289b351fae6b55e303f189127a394a1edd (patch)
tree77c9c35a31b1459dd7988c2448e797d142530c41 /tools
parent1a78a62555be32868418fe52f8e330c9d0f95d5a (diff)
downloadboost-bb4dd8289b351fae6b55e303f189127a394a1edd.tar.gz
boost-bb4dd8289b351fae6b55e303f189127a394a1edd.tar.bz2
boost-bb4dd8289b351fae6b55e303f189127a394a1edd.zip
Imported Upstream version 1.51.0upstream/1.51.0
Diffstat (limited to 'tools')
-rw-r--r--tools/bcp/copy_path.cpp14
-rw-r--r--tools/bcp/fileview.cpp2
-rw-r--r--tools/bcp/licence_info.cpp2
-rw-r--r--tools/bcp/main.cpp2
-rw-r--r--tools/bcp/output_licence_info.cpp2
-rw-r--r--tools/bcp/scan_cvs_path.cpp2
-rw-r--r--tools/bcp/scan_licence.cpp4
-rw-r--r--tools/boostbook/doc/boostbook.xml2
-rw-r--r--tools/boostbook/doc/documenting.xml6
-rw-r--r--tools/boostbook/doc/reference.xml128
-rw-r--r--tools/boostbook/doc/together.xml2
-rw-r--r--tools/boostbook/dtd/1.1/boostbook.dtd2
-rw-r--r--tools/boostbook/dtd/boostbook.dtd2
-rw-r--r--tools/boostbook/xsl/annotation.xsl6
-rw-r--r--tools/boostbook/xsl/docbook.xsl12
-rw-r--r--tools/boostbook/xsl/lookup.xsl2
-rw-r--r--tools/boostbook/xsl/source-highlight.xsl96
-rw-r--r--tools/build/v2/Jamroot.jam2
-rw-r--r--tools/build/v2/bootstrap.bat2
-rw-r--r--tools/build/v2/build/engine.py11
-rw-r--r--tools/build/v2/build/feature.py4
-rw-r--r--tools/build/v2/build/generators.jam76
-rw-r--r--tools/build/v2/build/generators.py36
-rw-r--r--tools/build/v2/build/project.jam201
-rw-r--r--tools/build/v2/build/property-set.jam184
-rw-r--r--tools/build/v2/build/property.py4
-rw-r--r--tools/build/v2/build/targets.jam2
-rw-r--r--tools/build/v2/build/targets.py3
-rw-r--r--tools/build/v2/build/toolset.jam75
-rw-r--r--tools/build/v2/build/toolset.py11
-rw-r--r--tools/build/v2/build/type.py2
-rw-r--r--tools/build/v2/build/version.jam2
-rw-r--r--tools/build/v2/build_system.py37
-rw-r--r--tools/build/v2/doc/src/abstract-target.xml126
-rw-r--r--tools/build/v2/doc/src/basic-target.xml96
-rw-r--r--tools/build/v2/doc/src/catalog.xml9
-rw-r--r--tools/build/v2/doc/src/extending.xml71
-rw-r--r--tools/build/v2/doc/src/faq.xml18
-rw-r--r--tools/build/v2/doc/src/howto.xml2
-rw-r--r--tools/build/v2/doc/src/install.xml8
-rw-r--r--tools/build/v2/doc/src/main-target.xml59
-rw-r--r--tools/build/v2/doc/src/overview.xml176
-rw-r--r--tools/build/v2/doc/src/path.xml248
-rw-r--r--tools/build/v2/doc/src/project-target.xml144
-rw-r--r--tools/build/v2/doc/src/property-set.xml128
-rw-r--r--tools/build/v2/doc/src/reference.xml286
-rw-r--r--tools/build/v2/doc/src/standalone.xml2
-rw-r--r--tools/build/v2/doc/src/tasks.xml178
-rw-r--r--tools/build/v2/doc/src/tutorial.xml119
-rw-r--r--tools/build/v2/doc/src/type.xml236
-rw-r--r--tools/build/v2/doc/src/typed-target.xml106
-rw-r--r--tools/build/v2/doc/src/userman.xml2
-rw-r--r--tools/build/v2/engine/build.bat42
-rw-r--r--tools/build/v2/engine/build.jam109
-rwxr-xr-xtools/build/v2/engine/build.sh6
-rw-r--r--tools/build/v2/engine/build_vms.com105
-rw-r--r--tools/build/v2/engine/builtins.c924
-rw-r--r--tools/build/v2/engine/builtins.h81
-rw-r--r--tools/build/v2/engine/class.c96
-rw-r--r--tools/build/v2/engine/class.h3
-rw-r--r--tools/build/v2/engine/command.c34
-rw-r--r--tools/build/v2/engine/command.h11
-rw-r--r--tools/build/v2/engine/compile.c1163
-rw-r--r--tools/build/v2/engine/compile.h29
-rw-r--r--tools/build/v2/engine/constants.c183
-rw-r--r--tools/build/v2/engine/constants.h72
-rw-r--r--tools/build/v2/engine/debug.c35
-rw-r--r--tools/build/v2/engine/debug.h9
-rw-r--r--tools/build/v2/engine/execcmd.h10
-rw-r--r--tools/build/v2/engine/execmac.c69
-rw-r--r--tools/build/v2/engine/execnt.c65
-rw-r--r--tools/build/v2/engine/execunix.c34
-rw-r--r--tools/build/v2/engine/execvms.c161
-rw-r--r--tools/build/v2/engine/expand.c733
-rw-r--r--tools/build/v2/engine/expand.h14
-rw-r--r--tools/build/v2/engine/filemac.c175
-rw-r--r--tools/build/v2/engine/filent.c96
-rw-r--r--tools/build/v2/engine/fileos2.c138
-rw-r--r--tools/build/v2/engine/filesys.c52
-rw-r--r--tools/build/v2/engine/filesys.h21
-rw-r--r--tools/build/v2/engine/fileunix.c84
-rw-r--r--tools/build/v2/engine/filevms.c327
-rw-r--r--tools/build/v2/engine/frames.c3
-rw-r--r--tools/build/v2/engine/frames.h14
-rw-r--r--tools/build/v2/engine/function.c4553
-rw-r--r--tools/build/v2/engine/function.h46
-rw-r--r--tools/build/v2/engine/glob.c10
-rw-r--r--tools/build/v2/engine/hash.c333
-rw-r--r--tools/build/v2/engine/hash.h65
-rw-r--r--tools/build/v2/engine/hcache.c334
-rw-r--r--tools/build/v2/engine/hcache.h6
-rw-r--r--tools/build/v2/engine/hdrmacro.c49
-rw-r--r--tools/build/v2/engine/hdrmacro.h7
-rw-r--r--tools/build/v2/engine/headers.c61
-rw-r--r--tools/build/v2/engine/headers.h13
-rw-r--r--tools/build/v2/engine/jam.c182
-rw-r--r--tools/build/v2/engine/jam.h83
-rw-r--r--tools/build/v2/engine/jamgram.c1687
-rw-r--r--tools/build/v2/engine/jamgram.h47
-rw-r--r--tools/build/v2/engine/jamgram.y52
-rw-r--r--tools/build/v2/engine/jamgram.yy50
-rw-r--r--tools/build/v2/engine/lists.c397
-rw-r--r--tools/build/v2/engine/lists.h50
-rw-r--r--tools/build/v2/engine/make.c95
-rw-r--r--tools/build/v2/engine/make.h14
-rw-r--r--tools/build/v2/engine/make1.c249
-rw-r--r--tools/build/v2/engine/modules.c394
-rw-r--r--tools/build/v2/engine/modules.h42
-rw-r--r--tools/build/v2/engine/modules/order.c41
-rw-r--r--tools/build/v2/engine/modules/path.c10
-rw-r--r--tools/build/v2/engine/modules/property-set.c39
-rw-r--r--tools/build/v2/engine/modules/regex.c24
-rw-r--r--tools/build/v2/engine/modules/sequence.c23
-rw-r--r--tools/build/v2/engine/modules/set.c14
-rw-r--r--tools/build/v2/engine/native.c47
-rw-r--r--tools/build/v2/engine/native.h13
-rw-r--r--tools/build/v2/engine/newstr.c174
-rw-r--r--tools/build/v2/engine/newstr.h14
-rw-r--r--tools/build/v2/engine/object.c379
-rw-r--r--tools/build/v2/engine/object.h43
-rw-r--r--tools/build/v2/engine/output.c14
-rw-r--r--tools/build/v2/engine/output.h7
-rw-r--r--tools/build/v2/engine/parse.c44
-rw-r--r--tools/build/v2/engine/parse.h47
-rw-r--r--tools/build/v2/engine/patchlevel.h8
-rw-r--r--tools/build/v2/engine/pathmac.c252
-rw-r--r--tools/build/v2/engine/pathsys.h34
-rw-r--r--tools/build/v2/engine/pathunix.c338
-rw-r--r--tools/build/v2/engine/pathvms.c406
-rw-r--r--tools/build/v2/engine/pwd.c20
-rw-r--r--tools/build/v2/engine/pwd.h3
-rw-r--r--tools/build/v2/engine/regexp.c32
-rw-r--r--tools/build/v2/engine/regexp.h10
-rw-r--r--tools/build/v2/engine/rules.c350
-rw-r--r--tools/build/v2/engine/rules.h67
-rw-r--r--tools/build/v2/engine/scan.c41
-rw-r--r--tools/build/v2/engine/scan.h21
-rw-r--r--tools/build/v2/engine/search.c145
-rw-r--r--tools/build/v2/engine/search.h11
-rw-r--r--tools/build/v2/engine/subst.c57
-rw-r--r--tools/build/v2/engine/timestamp.c141
-rw-r--r--tools/build/v2/engine/timestamp.h10
-rw-r--r--tools/build/v2/engine/variable.c460
-rw-r--r--tools/build/v2/engine/variable.h23
-rw-r--r--tools/build/v2/engine/w32_getreg.c34
-rw-r--r--tools/build/v2/test/BoostBuild.py58
-rw-r--r--tools/build/v2/test/Jamrules4
-rw-r--r--tools/build/v2/test/absolute_sources.py1
-rw-r--r--tools/build/v2/test/assert-equal.jam33
-rwxr-xr-xtools/build/v2/test/builtin_echo.py30
-rwxr-xr-xtools/build/v2/test/builtin_exit.py54
-rw-r--r--tools/build/v2/test/check-arguments.jam71
-rw-r--r--tools/build/v2/test/check-jam-patches.jam293
-rw-r--r--tools/build/v2/test/check-test-tools.jam26
-rwxr-xr-xtools/build/v2/test/conditionals_multiple.py19
-rwxr-xr-xtools/build/v2/test/configuration.py8
-rw-r--r--tools/build/v2/test/core-language/test.jam1353
-rwxr-xr-xtools/build/v2/test/core_action_status.py27
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_actions_quietly.py (renamed from tools/build/v2/test/engine/actions_quietly.jam)64
-rwxr-xr-xtools/build/v2/test/core_arguments.py109
-rwxr-xr-xtools/build/v2/test/core_at_file.py75
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_bindrule.py (renamed from tools/build/v2/test/check-bindrule.jam)20
-rw-r--r--tools/build/v2/test/core_import_module.py17
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_language.py (renamed from tools/build/v2/test/project-test1/dir2/jamfile.jam)13
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_nt_line_length.py (renamed from tools/build/v2/test/test_nt_line_length.jam)21
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_option_d2.py (renamed from tools/build/v2/test/engine/option_d2.jam)65
-rwxr-xr-xtools/build/v2/test/core_option_l.py47
-rwxr-xr-xtools/build/v2/test/core_option_n.py51
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_parallel_actions.py (renamed from tools/build/v2/test/engine/parallel_actions.jam)111
-rwxr-xr-xtools/build/v2/test/core_parallel_multifile_actions_1.py68
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_parallel_multifile_actions_2.py (renamed from tools/build/v2/test/engine/parallel_multifile_actions_2.jam)59
-rwxr-xr-xtools/build/v2/test/core_update_now.py198
-rw-r--r--tools/build/v2/test/direct-request-test/a.cpp19
-rw-r--r--tools/build/v2/test/direct-request-test/b.cpp22
-rw-r--r--tools/build/v2/test/direct-request-test/b_inverse.cpp22
-rw-r--r--tools/build/v2/test/direct-request-test/jamfile.jam13
-rw-r--r--tools/build/v2/test/direct-request-test/jamfile2.jam9
-rw-r--r--tools/build/v2/test/direct-request-test/jamroot.jam6
-rw-r--r--tools/build/v2/test/direct_request_test.py47
-rw-r--r--tools/build/v2/test/echo_args.jam20
-rw-r--r--tools/build/v2/test/empty.jam5
-rw-r--r--tools/build/v2/test/engine/README.txt5
-rw-r--r--tools/build/v2/test/engine/action_status.jam28
-rw-r--r--tools/build/v2/test/engine/builtin_normalize_path.jam60
-rw-r--r--tools/build/v2/test/engine/builtin_shell.jam31
-rw-r--r--tools/build/v2/test/engine/builtin_w32_getregnames.jam17
-rw-r--r--tools/build/v2/test/engine/option_l.jam34
-rw-r--r--tools/build/v2/test/engine/option_n.jam44
-rw-r--r--tools/build/v2/test/engine/parallel_multifile_actions_1.jam45
-rw-r--r--tools/build/v2/test/engine/rule_param.jam60
-rw-r--r--tools/build/v2/test/engine/stress_var_expand.jam14
-rw-r--r--tools/build/v2/test/engine/target_var.jam16
-rw-r--r--tools/build/v2/test/engine/test.bat53
-rw-r--r--tools/build/v2/test/engine/test.jam91
-rwxr-xr-xtools/build/v2/test/engine/test.sh53
-rw-r--r--tools/build/v2/test/engine/var_expand.jam19
-rwxr-xr-xtools/build/v2/test/file_name_handling.py255
-rw-r--r--tools/build/v2/test/jamfile.jam11
-rw-r--r--tools/build/v2/test/load_order.py24
-rw-r--r--tools/build/v2/test/m1-01.py61
-rw-r--r--tools/build/v2/test/m1-02.py90
-rw-r--r--tools/build/v2/test/m1-03.py57
-rw-r--r--tools/build/v2/test/prebuilt/ext/jamfile2.jam4
-rw-r--r--tools/build/v2/test/prebuilt/ext/jamfile3.jam4
-rw-r--r--tools/build/v2/test/project-test1.jam18
-rw-r--r--tools/build/v2/test/project-test1/dir/jamfile.jam10
-rw-r--r--tools/build/v2/test/project-test1/dir2/jamroot.jam4
-rw-r--r--tools/build/v2/test/project-test1/jamfile.jam10
-rw-r--r--tools/build/v2/test/project-test1/jamroot.jam6
-rw-r--r--tools/build/v2/test/project-test1/project-test1.jam21
-rw-r--r--tools/build/v2/test/project-test1/readme.txt8
-rw-r--r--tools/build/v2/test/project-test1/standalone-project.jam12
-rw-r--r--tools/build/v2/test/project_test1.py78
-rw-r--r--tools/build/v2/test/recursive.jam117
-rw-r--r--tools/build/v2/test/startup_v1.py81
-rw-r--r--tools/build/v2/test/subdir1/file-to-bind1
-rw-r--r--tools/build/v2/test/test.jam30
-rw-r--r--tools/build/v2/test/test1.py4
-rw-r--r--tools/build/v2/test/test2.py4
-rw-r--r--tools/build/v2/test/test2/Jamrules0
-rw-r--r--tools/build/v2/test/test2/jamroot.jam (renamed from tools/build/v2/test/test2/jamfile.jam)3
-rw-r--r--tools/build/v2/test/test_all.py21
-rw-r--r--tools/build/v2/test/testing-primitives/boost-build.jam5
-rw-r--r--tools/build/v2/test/testing-primitives/bootstrap.jam137
-rw-r--r--tools/build/v2/test/testing_primitives.py30
-rw-r--r--tools/build/v2/test/unit-tests.jam262
-rw-r--r--tools/build/v2/test/unused.py6
-rw-r--r--tools/build/v2/test/unused/jamroot.jam15
-rw-r--r--tools/build/v2/test/v1-testing/a.cpp5
-rw-r--r--tools/build/v2/test/v1-testing/b.cpp5
-rw-r--r--tools/build/v2/test/v1-testing/boost-build.jam6
-rw-r--r--tools/build/v2/test/v1-testing/c.cpp16
-rw-r--r--tools/build/v2/test/v1-testing/jamfile.jam26
-rw-r--r--tools/build/v2/test/v1_testing.py88
-rw-r--r--tools/build/v2/test/v1_testing/Jamrules0
-rw-r--r--tools/build/v2/test/v1_testing/boost-build.jam6
-rw-r--r--tools/build/v2/test/v1_testing/foo.cpp22
-rw-r--r--tools/build/v2/test/v1_testing/jamfile.jam23
-rw-r--r--tools/build/v2/test/v1_testing/jamroot.jam5
-rw-r--r--tools/build/v2/test/v1_testing/lib-err.cpp7
-rw-r--r--tools/build/v2/test/v1_testing/lib.cpp6
-rw-r--r--tools/build/v2/tools/auto-index.jam4
-rw-r--r--tools/build/v2/tools/boostbook.jam3
-rw-r--r--tools/build/v2/tools/builtin.py131
-rw-r--r--tools/build/v2/tools/cast.jam2
-rw-r--r--tools/build/v2/tools/common.jam13
-rw-r--r--tools/build/v2/tools/common.py16
-rw-r--r--tools/build/v2/tools/cray.jam112
-rw-r--r--tools/build/v2/tools/darwin.jam27
-rw-r--r--tools/build/v2/tools/docutils.jam1
-rw-r--r--tools/build/v2/tools/gcc.jam21
-rw-r--r--tools/build/v2/tools/gcc.py14
-rw-r--r--tools/build/v2/tools/intel-win.jam4
-rw-r--r--tools/build/v2/tools/mc.py46
-rw-r--r--tools/build/v2/tools/midl.py134
-rw-r--r--tools/build/v2/tools/msvc.jam10
-rw-r--r--tools/build/v2/tools/msvc.py1198
-rw-r--r--tools/build/v2/tools/pch.py14
-rw-r--r--tools/build/v2/tools/python.jam2
-rw-r--r--tools/build/v2/tools/stage.jam2
-rw-r--r--tools/build/v2/tools/stage.py2
-rw-r--r--tools/build/v2/tools/types/__init__.py1
-rw-r--r--tools/build/v2/tools/types/cpp.py5
-rw-r--r--tools/build/v2/tools/types/preprocessed.py11
-rw-r--r--tools/build/v2/tools/unix.py8
-rw-r--r--tools/build/v2/util/doc.jam2
-rw-r--r--tools/quickbook/doc/1_6.qbk84
-rw-r--r--tools/quickbook/doc/block.qbk120
-rw-r--r--tools/quickbook/doc/phrase.qbk104
-rw-r--r--tools/quickbook/doc/quickbook.qbk82
-rw-r--r--tools/quickbook/doc/structure.qbk7
-rw-r--r--tools/quickbook/doc/syntax.qbk6
-rw-r--r--tools/quickbook/src/Jamfile.v24
-rw-r--r--tools/quickbook/src/actions.cpp1154
-rw-r--r--tools/quickbook/src/actions.hpp151
-rw-r--r--tools/quickbook/src/actions_class.cpp136
-rw-r--r--tools/quickbook/src/block_element_grammar.cpp75
-rw-r--r--tools/quickbook/src/code_snippet.cpp88
-rw-r--r--tools/quickbook/src/doc_info_actions.cpp146
-rw-r--r--tools/quickbook/src/doc_info_grammar.cpp76
-rw-r--r--tools/quickbook/src/doc_info_tags.hpp1
-rw-r--r--tools/quickbook/src/files.cpp8
-rw-r--r--tools/quickbook/src/files.hpp29
-rw-r--r--tools/quickbook/src/fwd.hpp3
-rw-r--r--tools/quickbook/src/grammar.cpp8
-rw-r--r--tools/quickbook/src/grammar.hpp2
-rw-r--r--tools/quickbook/src/grammar_impl.hpp6
-rw-r--r--tools/quickbook/src/id_manager.cpp70
-rw-r--r--tools/quickbook/src/input_path.cpp79
-rw-r--r--tools/quickbook/src/input_path.hpp65
-rw-r--r--tools/quickbook/src/intrusive_base.hpp36
-rw-r--r--tools/quickbook/src/main_grammar.cpp464
-rw-r--r--tools/quickbook/src/parsers.hpp43
-rw-r--r--tools/quickbook/src/phrase_element_grammar.cpp87
-rw-r--r--tools/quickbook/src/phrase_tags.hpp7
-rw-r--r--tools/quickbook/src/quickbook.cpp136
-rw-r--r--tools/quickbook/src/quickbook.hpp4
-rw-r--r--tools/quickbook/src/state.cpp160
-rw-r--r--tools/quickbook/src/state.hpp (renamed from tools/quickbook/src/actions_class.hpp)53
-rw-r--r--tools/quickbook/src/state_save.hpp (renamed from tools/quickbook/src/actions_state.hpp)10
-rw-r--r--tools/quickbook/src/string_ref.cpp7
-rw-r--r--tools/quickbook/src/string_ref.hpp11
-rw-r--r--tools/quickbook/src/syntax_highlight.cpp400
-rw-r--r--tools/quickbook/src/utils.cpp19
-rw-r--r--tools/quickbook/src/utils.hpp11
-rw-r--r--tools/quickbook/src/values.cpp23
-rw-r--r--tools/quickbook/src/values.hpp6
-rw-r--r--tools/quickbook/test/Jamfile.v26
-rw-r--r--tools/quickbook/test/callouts-1_7.gold247
-rw-r--r--tools/quickbook/test/callouts-1_7.quickbook68
-rw-r--r--tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook4
-rw-r--r--tools/quickbook/test/doc-info/Jamfile.v22
-rw-r--r--tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold16
-rw-r--r--tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook11
-rw-r--r--tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold12
-rw-r--r--tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook10
-rw-r--r--tools/quickbook/test/link-1_7.gold44
-rw-r--r--tools/quickbook/test/link-1_7.quickbook52
-rw-r--r--tools/quickbook/test/list_test-1_5.gold16
-rw-r--r--tools/quickbook/test/list_test-1_5.quickbook8
-rw-r--r--tools/quickbook/test/list_test-1_6.gold50
-rw-r--r--tools/quickbook/test/list_test-1_6.quickbook21
-rw-r--r--tools/quickbook/test/python/include_path.qbk4
-rw-r--r--tools/quickbook/test/python/include_path_deps.txt3
-rw-r--r--tools/quickbook/test/python/include_path_locs.txt6
-rw-r--r--tools/quickbook/test/python/missing_relative.qbk6
-rw-r--r--tools/quickbook/test/python/missing_relative_deps.txt1
-rw-r--r--tools/quickbook/test/python/missing_relative_locs.txt4
-rw-r--r--tools/quickbook/test/python/output-deps.py151
-rw-r--r--tools/quickbook/test/python/sub1/a.qbk1
-rw-r--r--tools/quickbook/test/python/sub2/b.qbk1
-rw-r--r--tools/quickbook/test/python/svg_missing.qbk3
-rw-r--r--tools/quickbook/test/python/svg_missing_deps.txt1
-rw-r--r--tools/quickbook/test/python/svg_missing_locs.txt2
-rw-r--r--tools/quickbook/test/source_mode-1_7.gold38
-rw-r--r--tools/quickbook/test/source_mode-1_7.quickbook12
-rw-r--r--tools/quickbook/test/unit/Jamfile.v27
-rw-r--r--tools/quickbook/test/version-1_8-fail.quickbook (renamed from tools/quickbook/test/version-1_7-fail.quickbook)2
-rw-r--r--tools/regression/doc/index.html2
-rw-r--r--tools/regression/doc/library_status.html2
-rw-r--r--tools/regression/src/regression.py2
-rw-r--r--tools/wave/cpp.cpp397
-rw-r--r--tools/wave/cpp.hpp2
-rw-r--r--tools/wave/cpp_config.hpp2
-rw-r--r--tools/wave/cpp_version.hpp6
-rw-r--r--tools/wave/stop_watch.hpp2
-rw-r--r--tools/wave/trace_macro_expansion.hpp423
347 files changed, 19776 insertions, 12932 deletions
diff --git a/tools/bcp/copy_path.cpp b/tools/bcp/copy_path.cpp
index 4fe897d43d..497dcd5c86 100644
--- a/tools/bcp/copy_path.cpp
+++ b/tools/bcp/copy_path.cpp
@@ -134,7 +134,7 @@ void bcp_implementation::copy_path(const fs::path& p)
"(?|"
"(namespace\\s+)boost(_\\w+)?(?:(\\s*::\\s*)phoenix)?"
"|"
- "(namespace\\s+)(adstl|phoenix|rapidxml)\\>"
+ "(namespace\\s+(?:detail::)?)(adstl|phoenix|rapidxml)\\>"
"|"
"()\\<boost((?:_(?!intrusive_tags)\\w+)?\\s*(?:::))(?:(\\s*)phoenix)?"
"|"
@@ -154,11 +154,15 @@ void bcp_implementation::copy_path(const fs::path& p)
"|"
"(BOOST_CLASS_REQUIRE4?[^;]*)boost((?:_\\w+)?\\s*,)"
"|"
+ "(::tr1::|TR1_DECL\\s+)boost(_\\w+\\s*)" // math tr1
+ "|"
+ "(\\(\\s*)boost(\\s*\\))\\s*(\\(\\s*)phoenix(\\s*\\))"
+ "|"
"(\\(\\s*)boost(\\s*\\))"
")"
);
- regex_replace(std::back_inserter(v2), v1.begin(), v1.end(), namespace_matcher, "$1" + m_namespace_name + "$2(?3$3" + m_namespace_name + "phoenix)", boost::regex_constants::format_all);
+ regex_replace(std::back_inserter(v2), v1.begin(), v1.end(), namespace_matcher, "$1" + m_namespace_name + "$2(?3$3" + m_namespace_name + "phoenix?4$4)", boost::regex_constants::format_all);
std::swap(v1, v2);
v2.clear();
@@ -191,11 +195,11 @@ void bcp_implementation::copy_path(const fs::path& p)
"\\s*\\{.*"
"\\})([^\\{\\};]*)\\z"
*/
- "namespace\\s+" + m_namespace_name +
- "\\s*\\{"
+ "(namespace)(\\s+)(" + m_namespace_name + ")"
+ "(adstl|phoenix|rapidxml)?(\\s*\\{)"
);
regex_replace(std::back_inserter(v2), v1.begin(), v1.end(), namespace_alias,
- "namespace " + m_namespace_name + "{} namespace boost = " + m_namespace_name + "; namespace " + m_namespace_name + "{");
+ "$1 $3$4 {} $1 (?4$4:boost) = $3$4; $1$2$3$4$5", boost::regex_constants::format_all);
std::swap(v1, v2);
v2.clear();
}
diff --git a/tools/bcp/fileview.cpp b/tools/bcp/fileview.cpp
index 761756c156..54b3758551 100644
--- a/tools/bcp/fileview.cpp
+++ b/tools/bcp/fileview.cpp
@@ -38,7 +38,7 @@ fileview::~fileview()
{
}
-fileview::fileview(const fileview& that)
+fileview::fileview(const fileview& )
{
}
diff --git a/tools/bcp/licence_info.cpp b/tools/bcp/licence_info.cpp
index ab34b83c48..0e527fa488 100644
--- a/tools/bcp/licence_info.cpp
+++ b/tools/bcp/licence_info.cpp
@@ -705,7 +705,7 @@ std::pair<const license_info*, int> get_licenses()
)
,
};
- return std::pair<const license_info*, int>(licenses, sizeof(licenses)/sizeof(licenses[0]));
+ return std::pair<const license_info*, int>(licenses, static_cast<int>(sizeof(licenses)/sizeof(licenses[0])));
}
std::string format_authors_name(const std::string& name)
diff --git a/tools/bcp/main.cpp b/tools/bcp/main.cpp
index 28a5491e7c..aab15029d1 100644
--- a/tools/bcp/main.cpp
+++ b/tools/bcp/main.cpp
@@ -47,7 +47,7 @@ void show_usage()
"output-path: the path to which files will be copied\n";
}
-bool filesystem_name_check( const std::string & name )
+bool filesystem_name_check( const std::string & )
{
return true;
}
diff --git a/tools/bcp/output_licence_info.cpp b/tools/bcp/output_licence_info.cpp
index 2349acc83f..d42268fdbf 100644
--- a/tools/bcp/output_licence_info.cpp
+++ b/tools/bcp/output_licence_info.cpp
@@ -28,6 +28,8 @@ struct split_path
const fs::path& file;
split_path(const fs::path& r, const fs::path& f)
: root(r), file(f){}
+private:
+ split_path& operator=(const split_path&);
};
std::ostream& operator << (std::ostream& os, const split_path& p)
diff --git a/tools/bcp/scan_cvs_path.cpp b/tools/bcp/scan_cvs_path.cpp
index 3c5eb2ea58..6d2eb3a600 100644
--- a/tools/bcp/scan_cvs_path.cpp
+++ b/tools/bcp/scan_cvs_path.cpp
@@ -31,7 +31,7 @@ void bcp_implementation::scan_cvs_path(const fs::path& p)
static const boost::regex dir_expression("^(?:A\\s+)?D/([^/\\n]+)/");
static const int file_subs[] = {1,2,};
- for(int entry = 0; entry < sizeof(file_list)/sizeof(file_list[0]); ++entry)
+ for(std::size_t entry = 0; entry < sizeof(file_list)/sizeof(file_list[0]); ++entry)
{
fs::path entries(m_boost_path / p / file_list[entry]);
if(fs::exists(entries))
diff --git a/tools/bcp/scan_licence.cpp b/tools/bcp/scan_licence.cpp
index d1bf0bbebb..c061583a2c 100644
--- a/tools/bcp/scan_licence.cpp
+++ b/tools/bcp/scan_licence.cpp
@@ -27,8 +27,8 @@ context_before_license(const fileview& v, fileview::const_iterator start,
{
char last_char = '\0';
while (start != v.begin() && context_lines >= 0) {
- if (*start == '\r' || *start == '\n'
- && (last_char == *start || (last_char != '\r' && last_char != '\n')))
+ if ((*start == '\r') || (*start == '\n')
+ && ((last_char == *start) || ((last_char != '\r') && (last_char != '\n'))))
--context_lines;
last_char = *start;
diff --git a/tools/boostbook/doc/boostbook.xml b/tools/boostbook/doc/boostbook.xml
index d72373504e..1e57966fd5 100644
--- a/tools/boostbook/doc/boostbook.xml
+++ b/tools/boostbook/doc/boostbook.xml
@@ -9,7 +9,7 @@
<!DOCTYPE part PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude" id="boostbook"
- last-revision="$Date: 2010-07-19 19:29:09 -0400 (Mon, 19 Jul 2010) $">
+ last-revision="$Date: 2010-07-19 16:29:09 -0700 (Mon, 19 Jul 2010) $">
<partinfo>
<author>
<firstname>Douglas</firstname>
diff --git a/tools/boostbook/doc/documenting.xml b/tools/boostbook/doc/documenting.xml
index 64b73a80f9..04552e5f5a 100644
--- a/tools/boostbook/doc/documenting.xml
+++ b/tools/boostbook/doc/documenting.xml
@@ -9,7 +9,7 @@
<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<chapter xmlns:xi="http://www.w3.org/2001/XInclude" id="boostbook.documenting"
- last-revision="$Date: 2008-07-12 15:30:45 -0400 (Sat, 12 Jul 2008) $">
+ last-revision="$Date: 2008-07-12 12:30:45 -0700 (Sat, 12 Jul 2008) $">
<title>Documenting libraries</title>
<para>BoostBook is an extension to <ulink
@@ -40,7 +40,7 @@
&lt;!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"&gt;
&lt;library name="Any" dirname="any" xmlns:xi="http://www.w3.org/2001/XInclude"
- id="any" last-revision="$Date: 2008-07-12 15:30:45 -0400 (Sat, 12 Jul 2008) $"&gt;
+ id="any" last-revision="$Date: 2008-07-12 12:30:45 -0700 (Sat, 12 Jul 2008) $"&gt;
&lt;libraryinfo&gt;
&lt;author&gt;
&lt;firstname&gt;Kevlin&lt;/firstname&gt;
@@ -99,7 +99,7 @@
<varlistentry>
<term><code>last-revision</code></term>
<listitem>
- <simpara>Always set to <code>$Date: 2008-07-12 15:30:45 -0400 (Sat, 12 Jul 2008) $</code>, which is
+ <simpara>Always set to <code>$Date: 2008-07-12 12:30:45 -0700 (Sat, 12 Jul 2008) $</code>, which is
expanded by CVS to include the date and time that the file
was last modified.</simpara>
</listitem>
diff --git a/tools/boostbook/doc/reference.xml b/tools/boostbook/doc/reference.xml
index 783e44d92e..67aa7913a3 100644
--- a/tools/boostbook/doc/reference.xml
+++ b/tools/boostbook/doc/reference.xml
@@ -36,7 +36,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -140,7 +140,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -176,7 +176,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -218,7 +218,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -258,7 +258,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -294,7 +294,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>pack</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to '1' if the parameter is a parameter pack.</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -340,7 +340,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -378,7 +378,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -441,7 +441,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -481,7 +481,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -516,7 +516,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -555,7 +555,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>access</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The access specifier ("public", "private", or "protected") of the inheritance.</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>pack</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to '1' if this is a pack exapansion.</entry></row>
@@ -599,7 +599,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -717,7 +717,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -754,7 +754,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>alt</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
</tbody>
@@ -789,7 +789,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -863,7 +863,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>cv</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>cv-qualifiers for this method, e.g., const volatile</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
@@ -939,7 +939,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -991,7 +991,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1050,7 +1050,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>alt</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
</tbody>
@@ -1085,7 +1085,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1129,7 +1129,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>alt</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1165,7 +1165,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1201,7 +1201,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1236,7 +1236,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -1273,7 +1273,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1308,7 +1308,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1344,7 +1344,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1379,7 +1379,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>pack</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to '1' if this is a pack exapansion.</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1415,7 +1415,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>alt</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
</tbody>
@@ -1450,7 +1450,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1528,7 +1528,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1563,7 +1563,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1598,7 +1598,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -1668,7 +1668,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1712,7 +1712,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>cv</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>cv-qualifiers for this method, e.g., const volatile</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -1783,7 +1783,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1852,7 +1852,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1887,7 +1887,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -1965,7 +1965,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>cv</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>cv-qualifiers for this method, e.g., const volatile</entry></row>
<row><entry>specifiers</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>The specifiers for this function, e.g., inline, static, etc.</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -2007,7 +2007,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2046,7 +2046,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the access specification, e.g. "public", "private", or "protected".</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
</tbody>
@@ -2126,7 +2126,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2165,7 +2165,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2201,7 +2201,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2236,7 +2236,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2277,7 +2277,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2346,7 +2346,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2381,7 +2381,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2416,7 +2416,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>pack</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to '1' if the parameter is a parameter pack.</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
@@ -2453,7 +2453,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>dirname</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry/></row>
<row><entry>url</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
@@ -2497,7 +2497,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2532,7 +2532,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2568,7 +2568,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>alt</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry/></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
</tbody>
@@ -2603,7 +2603,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2639,7 +2639,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2692,7 +2692,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2728,7 +2728,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2763,7 +2763,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2798,7 +2798,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2833,7 +2833,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2868,7 +2868,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
@@ -2903,7 +2903,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>name</entry><entry>#REQUIRED</entry><entry>CDATA</entry><entry>The name of the element being declared to referenced</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
@@ -2939,7 +2939,7 @@
</thead>
<tbody>
-<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 10:53:46 -0400 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
+<row><entry>last-revision</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Set to $Date: 2009-10-10 07:53:46 -0700 (Sat, 10 Oct 2009) $ to keep "last revised" information in sync with CVS changes</entry></row>
<row><entry>id</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>A global identifier for this element</entry></row>
<row><entry>xml:base</entry><entry>#IMPLIED</entry><entry>CDATA</entry><entry>Implementation detail used by XIncludes</entry></row>
</tbody>
diff --git a/tools/boostbook/doc/together.xml b/tools/boostbook/doc/together.xml
index 2b35b7840c..ca93fc53b7 100644
--- a/tools/boostbook/doc/together.xml
+++ b/tools/boostbook/doc/together.xml
@@ -9,7 +9,7 @@
<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<chapter xmlns:xi="http://www.w3.org/2001/XInclude" id="boostbook.together"
- last-revision="$Date: 2009-04-15 03:37:45 -0400 (Wed, 15 Apr 2009) $">
+ last-revision="$Date: 2009-04-15 00:37:45 -0700 (Wed, 15 Apr 2009) $">
<title>Bringing Together a BoostBook Document</title>
<section id="boostbook.linking">
diff --git a/tools/boostbook/dtd/1.1/boostbook.dtd b/tools/boostbook/dtd/1.1/boostbook.dtd
index 85a73dd28f..ec2086aebf 100644
--- a/tools/boostbook/dtd/1.1/boostbook.dtd
+++ b/tools/boostbook/dtd/1.1/boostbook.dtd
@@ -17,7 +17,7 @@
SYSTEM "http://www.boost.org/tools/boostbook/dtd/1.1/boostbook.dtd"
$Revision: 55188 $
- $Date: 2009-07-26 16:11:03 -0400 (Sun, 26 Jul 2009) $
+ $Date: 2009-07-26 13:11:03 -0700 (Sun, 26 Jul 2009) $
-->
<!--========== Define XInclude features. ==========-->
diff --git a/tools/boostbook/dtd/boostbook.dtd b/tools/boostbook/dtd/boostbook.dtd
index df7db295a1..4718abe39c 100644
--- a/tools/boostbook/dtd/boostbook.dtd
+++ b/tools/boostbook/dtd/boostbook.dtd
@@ -17,7 +17,7 @@
SYSTEM "http://www.boost.org/tools/boostbook/dtd/1.1/boostbook.dtd"
$Revision: 51774 $
- $Date: 2009-03-14 07:42:38 -0400 (Sat, 14 Mar 2009) $
+ $Date: 2009-03-14 04:42:38 -0700 (Sat, 14 Mar 2009) $
-->
<!--========== Define XInclude features. ==========-->
diff --git a/tools/boostbook/xsl/annotation.xsl b/tools/boostbook/xsl/annotation.xsl
index 9f5a178586..ff847d3aac 100644
--- a/tools/boostbook/xsl/annotation.xsl
+++ b/tools/boostbook/xsl/annotation.xsl
@@ -388,6 +388,12 @@
</computeroutput>
</xsl:template>
+ <xsl:template match="code[@language='jam']" mode="annotation">
+ <computeroutput>
+ <xsl:apply-templates mode="annotation"/>
+ </computeroutput>
+ </xsl:template>
+
<xsl:template match="bold" mode="annotation">
<emphasis role="bold">
<xsl:apply-templates mode="annotation"/>
diff --git a/tools/boostbook/xsl/docbook.xsl b/tools/boostbook/xsl/docbook.xsl
index c2ad5218be..c4d50c5608 100644
--- a/tools/boostbook/xsl/docbook.xsl
+++ b/tools/boostbook/xsl/docbook.xsl
@@ -392,6 +392,12 @@ Error: XSL template 'link-or-anchor' called with invalid link-type '<xsl:value-o
</computeroutput>
</xsl:template>
+ <xsl:template match="code[@language='jam']">
+ <computeroutput>
+ <xsl:apply-templates mode="highlight-jam"/>
+ </computeroutput>
+ </xsl:template>
+
<xsl:template match="bold">
<emphasis role="bold">
<xsl:apply-templates mode="annotation"/>
@@ -447,6 +453,12 @@ Error: XSL template 'link-or-anchor' called with invalid link-type '<xsl:value-o
<programlisting><xsl:apply-templates/></programlisting>
</xsl:template>
+ <xsl:template match="programlisting[@language='jam']">
+ <programlisting>
+ <xsl:apply-templates mode="highlight-jam"/>
+ </programlisting>
+ </xsl:template>
+
<!-- These DocBook elements have special meaning. Use the annotation mode -->
<xsl:template match="classname|methodname|functionname|enumname|
macroname|headername|globalname">
diff --git a/tools/boostbook/xsl/lookup.xsl b/tools/boostbook/xsl/lookup.xsl
index d37e787a7a..46cb7c7bb7 100644
--- a/tools/boostbook/xsl/lookup.xsl
+++ b/tools/boostbook/xsl/lookup.xsl
@@ -236,7 +236,7 @@
<xsl:variable name="normalized" select="translate(normalize-space(translate($part, '.&lt;&gt;;\:*?&quot;|_', ' ')), ' ', '_')"/>
<xsl:value-of select =
"concat(
- substring($normalized, 1, $boost.max.id.part.length - string-length(generate-id(.) - 1)),
+ substring($normalized, 1, $boost.max.id.part.length - string-length(generate-id(.)) - 1),
concat('_', generate-id(.)))"/>
</xsl:when>
<xsl:otherwise>
diff --git a/tools/boostbook/xsl/source-highlight.xsl b/tools/boostbook/xsl/source-highlight.xsl
index b3903e5ba6..4945e38ab1 100644
--- a/tools/boostbook/xsl/source-highlight.xsl
+++ b/tools/boostbook/xsl/source-highlight.xsl
@@ -435,6 +435,92 @@
</xsl:choose>
</xsl:template>
+ <!-- Jam syntax highlighting -->
+
+ <xsl:variable name="jam-keywords" select="' actions bind case class default else for if ignore in include local module on piecemeal quietly return rule switch together updated while '"/>
+ <xsl:variable name="jam-operators" select="' ! != &amp; &amp;&amp; ( ) += : ; &lt; &lt;= = &gt; &gt;= ?= [ ] { | || } '"/>
+
+ <xsl:template name="highlight-jam-word">
+ <xsl:param name="text"/>
+ <xsl:choose>
+ <xsl:when test="contains($jam-keywords, concat(' ', $text, ' '))">
+ <xsl:call-template name="highlight-keyword">
+ <xsl:with-param name="keyword" select="$text"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="contains($jam-operators, concat(' ', $text, ' '))">
+ <xsl:call-template name="highlight-special">
+ <xsl:with-param name="text" select="$text"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="jam-word-length">
+ <xsl:param name="text"/>
+ <xsl:param name="pos" select="1"/>
+ <xsl:choose>
+ <xsl:when test="string-length($text) + 1= $pos">
+ <xsl:value-of select="$pos - 1"/>
+ </xsl:when>
+ <xsl:when test="contains(' &#xA;&#xD;&#x9;', substring($text, $pos, 1))">
+ <xsl:value-of select="$pos - 1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="jam-word-length">
+ <xsl:with-param name="text" select="$text"/>
+ <xsl:with-param name="pos" select="$pos + 1"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="highlight-jam-text">
+ <xsl:param name="text"/>
+ <xsl:choose>
+ <xsl:when test="string-length($text) = 0"/>
+ <xsl:when test="contains(' &#xA;&#xD;&#x9;', substring($text, 1, 1))">
+ <xsl:value-of select="substring($text, 1, 1)"/>
+ <xsl:call-template name="highlight-jam-text">
+ <xsl:with-param name="text" select="substring($text, 2)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="substring($text, 1, 1) = '#'">
+ <xsl:choose>
+ <xsl:when test="contains($text, '&#xA;')">
+ <xsl:call-template name="highlight-comment">
+ <xsl:with-param name="text" select="substring-before($text, '&#xA;')"/>
+ </xsl:call-template>
+ <xsl:call-template name="highlight-jam-text">
+ <xsl:with-param name="text" select="concat('&#xA;', substring-after($text, '&#xA;'))"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="highlight-comment">
+ <xsl:with-param name="text" select="$text"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="length">
+ <xsl:call-template name="jam-word-length">
+ <xsl:with-param name="text" select="$text"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:call-template name="highlight-jam-word">
+ <xsl:with-param name="text" select="substring($text, 1, $length)"/>
+ </xsl:call-template>
+ <xsl:call-template name="highlight-jam-text">
+ <xsl:with-param name="text" select="substring($text, $length + 1)"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- Perform C++ syntax highlighting on the given text -->
<xsl:template name="highlight-text">
<xsl:param name="text" select="."/>
@@ -481,4 +567,14 @@
<xsl:apply-templates mode="highlight"/>
</xsl:template>
+ <xsl:template match="*" mode="highlight-jam">
+ <xsl:apply-templates select="." mode="annotation"/>
+ </xsl:template>
+
+ <xsl:template match="text()" mode="highlight-jam">
+ <xsl:call-template name="highlight-jam-text">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ </xsl:template>
+
</xsl:stylesheet>
diff --git a/tools/build/v2/Jamroot.jam b/tools/build/v2/Jamroot.jam
index 11334864c2..73d86ab15b 100644
--- a/tools/build/v2/Jamroot.jam
+++ b/tools/build/v2/Jamroot.jam
@@ -38,7 +38,7 @@ package.install-data boost-build-core
[ path.glob-tree $(SELF)/build : *.jam *.py ]
[ path.glob-tree $(SELF)/kernel : *.jam *.py ]
[ path.glob-tree $(SELF)/util : *.jam *.py ]
- [ path.glob-tree $(SELF)/tools : *.jam *.py ]
+ [ path.glob-tree $(SELF)/tools : *.jam *.py *.xml *.xsl *.doxyfile *.hpp ]
$(e2)
: # What is the root of the directory
<install-source-root>.
diff --git a/tools/build/v2/bootstrap.bat b/tools/build/v2/bootstrap.bat
index 190c9283de..58f7613983 100644
--- a/tools/build/v2/bootstrap.bat
+++ b/tools/build/v2/bootstrap.bat
@@ -10,7 +10,7 @@ if exist ".\engine\bin.ntx86\bjam.exe" del engine\bin.ntx86\bjam.exe
if exist ".\engine\bin.ntx86_64\bjam.exe" del engine\bin.ntx86_64\bjam.exe
cd engine
-call .\build.bat %* > ..\..\bootstrap.log
+call .\build.bat %* > ..\bootstrap.log
@ECHO OFF
cd ..
diff --git a/tools/build/v2/build/engine.py b/tools/build/v2/build/engine.py
index be9736e06c..9e624dae82 100644
--- a/tools/build/v2/build/engine.py
+++ b/tools/build/v2/build/engine.py
@@ -20,14 +20,14 @@ class BjamAction:
self.function = function
def __call__(self, targets, sources, property_set):
- if self.function:
- self.function(targets, sources, property_set)
# Bjam actions defined from Python have only the command
# to execute, and no associated jam procedural code. So
# passing 'property_set' to it is not necessary.
bjam_interface.call("set-update-action", self.action_name,
targets, sources, [])
+ if self.function:
+ self.function(targets, sources, property_set)
class BjamNativeAction:
"""Class representing bjam action defined by Jam code.
@@ -132,7 +132,12 @@ class Engine:
bjam_flags = reduce(operator.or_,
(action_modifiers[flag] for flag in flags), 0)
- bjam_interface.define_action(action_name, command, bound_list, bjam_flags)
+ # We allow command to be empty so that we can define 'action' as pure
+ # python function that would do some conditional logic and then relay
+ # to other actions.
+ assert command or function
+ if command:
+ bjam_interface.define_action(action_name, command, bound_list, bjam_flags)
self.actions[action_name] = BjamAction(action_name, function)
diff --git a/tools/build/v2/build/feature.py b/tools/build/v2/build/feature.py
index 315a18e944..289aca14c5 100644
--- a/tools/build/v2/build/feature.py
+++ b/tools/build/v2/build/feature.py
@@ -557,10 +557,12 @@ def expand_composite(property):
result.extend(expand_composite(p))
return result
-
+@bjam_signature((['feature'], ['properties', '*']))
def get_values (feature, properties):
""" Returns all values of the given feature specified by the given property set.
"""
+ if feature[0] != '<':
+ feature = '<' + feature + '>'
result = []
for p in properties:
if get_grist (p) == feature:
diff --git a/tools/build/v2/build/generators.jam b/tools/build/v2/build/generators.jam
index 1515525f2d..333def5741 100644
--- a/tools/build/v2/build/generators.jam
+++ b/tools/build/v2/build/generators.jam
@@ -400,13 +400,13 @@ class generator
if $(self.composing)
{
- convert-multiple-sources-to-consumable-types $(project)
- : $(property-set) : $(sources) : consumed bypassed ;
+ consumed = [ convert-multiple-sources-to-consumable-types $(project)
+ : $(property-set) : $(sources) ] ;
}
else
{
- convert-to-consumable-types $(project) $(name) : $(property-set)
- : $(sources) : : consumed bypassed ;
+ consumed = [ convert-to-consumable-types $(project) $(name)
+ : $(property-set) : $(sources) ] ;
}
local result ;
@@ -579,16 +579,9 @@ class generator
: sources +
: only-one ? # Convert 'source' to only one of the source types. If
# there is more that one possibility, report an error.
- : consumed-var # Name of the variable which receives all targets which
- # can be consumed.
- bypassed-var # Name of the variable which receives all targets which
- # can not be consumed.
)
{
- # We are likely to be passed 'consumed' and 'bypassed' var names. Use
- # '_' to avoid name conflicts.
local _consumed ;
- local _bypassed ;
local missing-types ;
if $(sources[2])
@@ -599,7 +592,12 @@ class generator
}
else
{
- consume-directly $(sources) : _consumed : missing-types ;
+ local temp = [ consume-directly $(sources) ] ;
+ if $(temp[1])
+ {
+ _consumed = $(temp[1]) ;
+ }
+ missing-types = $(temp[2-]) ;
}
# No need to search for transformation if some source type has consumed
@@ -611,8 +609,6 @@ class generator
# TODO: we should check that only one source type if create of
# 'only-one' is true.
- # TODO: consider if consumed/bypassed separation should be done by
- # 'construct-types'.
if $(missing-types)
{
@@ -631,61 +627,35 @@ class generator
{
_consumed += $(t) ;
}
- else
- {
- _bypassed += $(t) ;
- }
}
}
- _consumed = [ sequence.unique $(_consumed) ] ;
- _bypassed = [ sequence.unique $(_bypassed) ] ;
-
- # Remove elements of '_bypassed' that are in '_consumed'.
-
- # Suppose the target type of current generator, X is produced from X_1
- # and X_2, which are produced from Y by one generator. When creating X_1
- # from Y, X_2 will be added to 'bypassed'. Likewise, when creating X_2
- # from Y, X_1 will be added to 'bypassed', but they are also in
- # 'consumed'. We have to remove them from bypassed, so that generators
- # up the call stack do not try to convert them.
-
- # In this particular case, X_1 instance in 'consumed' and X_1 instance
- # in 'bypassed' will be the same: because they have the same source and
- # action name, and 'virtual-target.register' will not allow two
- # different instances. Therefore, it is OK to use 'set.difference'.
-
- _bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
-
- $(consumed-var) += $(_consumed) ;
- $(bypassed-var) += $(_bypassed) ;
+ return [ sequence.unique $(_consumed) ] ;
}
# Converts several files to consumable types. Called for composing
# generators only.
#
rule convert-multiple-sources-to-consumable-types ( project : property-set :
- sources * : consumed-var bypassed-var )
+ sources * )
{
+ local result ;
# We process each source one-by-one, trying to convert it to a usable
# type.
for local source in $(sources)
{
- local _c ;
- local _b ;
- # TODO: need to check for failure on each source.
- convert-to-consumable-types $(project) : $(property-set) : $(source)
- : true : _c _b ;
+ local _c = [ convert-to-consumable-types $(project) : $(property-set)
+ : $(source) : true ] ;
if ! $(_c)
{
generators.dout [ indent ] " failed to convert " $(source) ;
}
- $(consumed-var) += $(_c) ;
- $(bypassed-var) += $(_b) ;
+ result += $(_c) ;
}
+ return $(result) ;
}
- rule consume-directly ( source : consumed-var : missing-types-var )
+ rule consume-directly ( source )
{
local real-source-type = [ $(source).type ] ;
@@ -693,19 +663,23 @@ class generator
local source-types = $(self.source-types) ;
source-types ?= $(real-source-type) ;
+ local result = "" ;
+ local missing-types ;
+
for local st in $(source-types)
{
# The 'source' if of the right type already.
if $(real-source-type) = $(st) || [ type.is-derived
$(real-source-type) $(st) ]
{
- $(consumed-var) += $(source) ;
+ result = $(source) ;
}
else
{
- $(missing-types-var) += $(st) ;
+ missing-types += $(st) ;
}
}
+ return $(result) $(missing-types) ;
}
# Returns the class to be used to actions. Default implementation returns
@@ -1072,7 +1046,6 @@ rule construct-types ( project name ? : target-types + : property-set
: sources + )
{
local result ;
- local matched-types ;
local usage-requirements = [ property-set.empty ] ;
for local t in $(target-types)
{
@@ -1082,7 +1055,6 @@ rule construct-types ( project name ? : target-types + : property-set
{
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
result += $(r[2-]) ;
- matched-types += $(t) ;
}
}
# TODO: have to introduce parameter controlling if several types can be
diff --git a/tools/build/v2/build/generators.py b/tools/build/v2/build/generators.py
index 2c59f7ca14..7c82645388 100644
--- a/tools/build/v2/build/generators.py
+++ b/tools/build/v2/build/generators.py
@@ -400,6 +400,9 @@ class Generator:
dir = os.path.dirname(fullname)
name = os.path.basename(fullname)
+ idx = name.find(".")
+ if idx != -1:
+ name = name[:idx]
if dir and not ".." in dir and not os.path.isabs(dir):
# Relative path is always relative to the source
@@ -470,9 +473,6 @@ class Generator:
post = self.name_postfix_
for t in self.target_types_:
basename = os.path.basename(name)
- idx = basename.find(".")
- if idx != -1:
- basename = basename[:idx]
generated_name = pre[0] + basename + post[0]
generated_name = os.path.join(os.path.dirname(name), generated_name)
pre = pre[1:]
@@ -692,7 +692,7 @@ def override (overrider_id, overridee_id):
after computing the list of viable generators, before
running any of them."""
- __overrides.get(overrider_id, []).append(overridee_id)
+ __overrides.setdefault(overrider_id, []).append(overridee_id)
def __viable_source_types_real (target_type):
""" Returns a list of source type which can possibly be converted
@@ -974,7 +974,7 @@ def find_viable_generators (target_type, prop_set):
# Generators which are overriden
overriden_ids = []
-
+
for g in viable_generators:
id = g.id ()
@@ -988,13 +988,7 @@ def find_viable_generators (target_type, prop_set):
if all_overrides:
viable_generators = all_overrides
- result = []
- for g in viable_generators:
- if not g.id () in overriden_ids:
- result.append (g)
-
-
- return result
+ return [g for g in viable_generators if not g.id() in overriden_ids]
def __construct_really (project, name, target_type, prop_set, sources):
""" Attempts to construct target by finding viable generators, running them
@@ -1004,7 +998,7 @@ def __construct_really (project, name, target_type, prop_set, sources):
result = []
- project.manager ().logger ().log (__name__, "*** %d viable generators" % len (viable_generators))
+ dout(" *** %d viable generators" % len (viable_generators))
generators_that_succeeded = []
@@ -1086,4 +1080,18 @@ def construct (project, name, target_type, prop_set, sources, top_level=False):
__active_generators = saved_active
return result
-
+
+def add_usage_requirements (result, raw_properties):
+ if result:
+ if isinstance (result[0], property_set.PropertySet):
+ return (result[0].add_raw(raw_properties), result[1])
+ else:
+ return (propery_set.create(raw-properties), result)
+ #if [ class.is-a $(result[1]) : property-set ]
+ #{
+ # return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
+ #}
+ #else
+ #{
+ # return [ property-set.create $(raw-properties) ] $(result) ;
+ #}
diff --git a/tools/build/v2/build/project.jam b/tools/build/v2/build/project.jam
index c9967613bc..0fae4d2004 100644
--- a/tools/build/v2/build/project.jam
+++ b/tools/build/v2/build/project.jam
@@ -263,7 +263,7 @@ rule find-jamfile (
{
errors.error Unable to load Jamfile.
: Could not find a Jamfile in directory '$(dir)'.
- : Attempted to find it with pattern '"$(JAMFILE:J=" ")"'.
+ : Attempted to find it with pattern '"$(JAMFILE:J= )"'.
: Please consult the documentation at 'http://www.boost.org'. ;
}
@@ -301,56 +301,60 @@ local rule load-jamfile (
# prevents that second attempt from messing up.
if ! $(jamfile-module) in $(.jamfile-modules)
{
- .jamfile-modules += $(jamfile-module) ;
# Initialize the Jamfile module before loading.
#
initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ]
: $(jamfile-to-load:BS) ;
- local saved-project = $(.current-project) ;
-
- mark-as-user $(jamfile-module) ;
- modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ] : . ;
- if [ MATCH ($(JAMROOT)) : $(jamfile-to-load:BS) ]
+ if ! $(jamfile-module) in $(.jamfile-modules)
{
- jamfile = [ find-jamfile $(dir) : no-errors ] ;
- if $(jamfile)
+ .jamfile-modules += $(jamfile-module) ;
+
+ local saved-project = $(.current-project) ;
+
+ mark-as-user $(jamfile-module) ;
+ modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ] : . ;
+ if [ MATCH ($(JAMROOT)) : $(jamfile-to-load:BS) ]
{
- load-aux $(jamfile-module) : [ path.native $(jamfile) ] ;
+ jamfile = [ find-jamfile $(dir) : no-errors ] ;
+ if $(jamfile)
+ {
+ load-aux $(jamfile-module) : [ path.native $(jamfile) ] ;
+ }
}
- }
-
- # Now do some checks.
- if $(.current-project) != $(saved-project)
- {
- errors.error "The value of the .current-project variable has magically"
- : "changed after loading a Jamfile. This means some of the targets"
- : "might be defined in the wrong project."
- : "after loading" $(jamfile-module)
- : "expected value" $(saved-project)
- : "actual value" $(.current-project) ;
- }
- if $(.global-build-dir)
- {
- local id = [ attribute $(jamfile-module) id ] ;
- local project-root = [ attribute $(jamfile-module) project-root ] ;
- local location = [ attribute $(jamfile-module) location ] ;
+ # Now do some checks.
+ if $(.current-project) != $(saved-project)
+ {
+ errors.error "The value of the .current-project variable has magically"
+ : "changed after loading a Jamfile. This means some of the targets"
+ : "might be defined in the wrong project."
+ : "after loading" $(jamfile-module)
+ : "expected value" $(saved-project)
+ : "actual value" $(.current-project) ;
+ }
- if $(location) && $(project-root) = $(dir)
- {
- # This is Jamroot.
- if ! $(id)
+ if $(.global-build-dir)
{
- ECHO "warning: the --build-dir option was specified" ;
- ECHO "warning: but Jamroot at '$(dir)'" ;
- ECHO "warning: specified no project id" ;
- ECHO "warning: the --build-dir option will be ignored" ;
+ local id = [ attribute $(jamfile-module) id ] ;
+ local project-root = [ attribute $(jamfile-module) project-root ] ;
+ local location = [ attribute $(jamfile-module) location ] ;
+
+ if $(location) && $(project-root) = $(dir)
+ {
+ # This is Jamroot.
+ if ! $(id)
+ {
+ ECHO "warning: the --build-dir option was specified" ;
+ ECHO "warning: but Jamroot at '$(dir)'" ;
+ ECHO "warning: specified no project id" ;
+ ECHO "warning: the --build-dir option will be ignored" ;
+ }
+ }
}
}
}
- }
}
@@ -398,44 +402,6 @@ rule initialize (
ECHO "Initializing project '$(module-name)'" ;
}
- # TODO: need to consider if standalone projects can do anything but define
- # prebuilt targets. If so, we need to give it a more sensible "location", so
- # that source paths are correct.
- location ?= "" ;
- # Create the module for the Jamfile first.
- module $(module-name)
- {
- }
- $(module-name).attributes = [ new project-attributes $(location)
- $(module-name) ] ;
- local attributes = $($(module-name).attributes) ;
-
- if $(location)
- {
- $(attributes).set source-location : [ path.make $(location) ] : exact ;
- }
- else if ! $(module-name) in test-config site-config user-config project-config
- {
- # This is a standalone project with known location. Set source location
- # so that it can declare targets. This is intended so that you can put
- # a .jam file in your sources and use it via 'using'. Standard modules
- # (in 'tools' subdir) may not assume source dir is set.
- local s = [ modules.binding $(module-name) ] ;
- if ! $(s)
- {
- errors.error "Could not determine project location $(module-name)" ;
- }
- $(attributes).set source-location : $(s:D) : exact ;
- }
-
- $(attributes).set requirements : [ property-set.empty ] : exact ;
- $(attributes).set usage-requirements : [ property-set.empty ] : exact ;
-
- # Import rules common to all project modules from project-rules module,
- # defined at the end of this file.
- local rules = [ RULENAMES project-rules ] ;
- IMPORT project-rules : $(rules) : $(module-name) : $(rules) ;
-
local jamroot ;
local parent-module ;
@@ -483,33 +449,77 @@ rule initialize (
}
}
- if $(parent-module)
+ # TODO: need to consider if standalone projects can do anything but define
+ # prebuilt targets. If so, we need to give it a more sensible "location", so
+ # that source paths are correct.
+ location ?= "" ;
+ # Create the module for the Jamfile first.
+ module $(module-name)
{
- inherit-attributes $(module-name) : $(parent-module) ;
- $(attributes).set parent-module : $(parent-module) : exact ;
}
- if $(jamroot)
- {
- $(attributes).set project-root : $(location) : exact ;
- }
+ # load-parent can end up loading this module again.
+ # Make sure this isn't duplicated.
+ if ! $($(module-name).attributes) {
- local parent ;
- if $(parent-module)
- {
- parent = [ target $(parent-module) ] ;
- }
+ $(module-name).attributes = [ new project-attributes $(location)
+ $(module-name) ] ;
+ local attributes = $($(module-name).attributes) ;
- if ! $(.target.$(module-name))
- {
- .target.$(module-name) = [ new project-target $(module-name)
- : $(module-name) $(parent)
- : [ attribute $(module-name) requirements ] ] ;
+ if $(location)
+ {
+ $(attributes).set source-location : [ path.make $(location) ] : exact ;
+ }
+ else if ! $(module-name) in test-config site-config user-config project-config
+ {
+ # This is a standalone project with known location. Set source location
+ # so that it can declare targets. This is intended so that you can put
+ # a .jam file in your sources and use it via 'using'. Standard modules
+ # (in 'tools' subdir) may not assume source dir is set.
+ local s = [ modules.binding $(module-name) ] ;
+ if ! $(s)
+ {
+ errors.error "Could not determine project location $(module-name)" ;
+ }
+ $(attributes).set source-location : $(s:D) : exact ;
+ }
+
+ $(attributes).set requirements : [ property-set.empty ] : exact ;
+ $(attributes).set usage-requirements : [ property-set.empty ] : exact ;
+
+ # Import rules common to all project modules from project-rules module,
+ # defined at the end of this file.
+ local rules = [ RULENAMES project-rules ] ;
+ IMPORT project-rules : $(rules) : $(module-name) : $(rules) ;
+
+ if $(parent-module)
+ {
+ inherit-attributes $(module-name) : $(parent-module) ;
+ $(attributes).set parent-module : $(parent-module) : exact ;
+ }
+
+ if $(jamroot)
+ {
+ $(attributes).set project-root : $(location) : exact ;
+ }
+
+ local parent ;
+ if $(parent-module)
+ {
+ parent = [ target $(parent-module) ] ;
+ }
- if --debug-loading in [ modules.peek : ARGV ]
+ if ! $(.target.$(module-name))
{
- ECHO "Assigned project target" $(.target.$(module-name))
- "to '$(module-name)'" ;
+ .target.$(module-name) = [ new project-target $(module-name)
+ : $(module-name) $(parent)
+ : [ attribute $(module-name) requirements ] ] ;
+
+ if --debug-loading in [ modules.peek : ARGV ]
+ {
+ ECHO "Assigned project target" $(.target.$(module-name))
+ "to '$(module-name)'" ;
+ }
}
}
@@ -1099,7 +1109,8 @@ module project-rules
rule option ( name : value )
{
- if $(__name__) != site-config && $(__name__) != user-config && $(__name__) != project-config
+ local m = [ CALLER_MODULE ] ;
+ if $(m) != site-config && $(m) != user-config && $(m) != project-config
{
import errors ;
errors.error "The 'option' rule may be used only in site-config or user-config" ;
diff --git a/tools/build/v2/build/property-set.jam b/tools/build/v2/build/property-set.jam
index 70fd90cde5..51e2b20de4 100644
--- a/tools/build/v2/build/property-set.jam
+++ b/tools/build/v2/build/property-set.jam
@@ -48,49 +48,6 @@ class property-set
{
errors.error "Invalid property: '$(p)'" ;
}
-
- local att = [ feature.attributes $(p:G) ] ;
- # A feature can be both incidental and free, in which case we add it
- # to incidental.
- if incidental in $(att)
- {
- self.incidental += $(p) ;
- }
- else if free in $(att)
- {
- self.free += $(p) ;
- }
- else
- {
- self.base += $(p) ;
- }
-
- if dependency in $(att)
- {
- self.dependency += $(p) ;
- }
- else
- {
- self.non-dependency += $(p) ;
- }
-
- if [ MATCH (:) : $(p:G=) ]
- {
- self.conditional += $(p) ;
- }
- else
- {
- self.non-conditional += $(p) ;
- }
-
- if propagated in $(att)
- {
- self.propagated += $(p) ;
- }
- if link-incompatible in $(att)
- {
- self.link-incompatible += $(p) ;
- }
}
}
@@ -110,6 +67,10 @@ class property-set
#
rule base ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.base) ;
}
@@ -117,6 +78,10 @@ class property-set
#
rule free ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.free) ;
}
@@ -124,21 +89,37 @@ class property-set
#
rule dependency ( )
{
+ if ! $(self.dependency-initialized)
+ {
+ init-dependency ;
+ }
return $(self.dependency) ;
}
rule non-dependency ( )
{
+ if ! $(self.dependency-initialized)
+ {
+ init-dependency ;
+ }
return $(self.non-dependency) ;
}
rule conditional ( )
{
+ if ! $(self.conditional-initialized)
+ {
+ init-conditional ;
+ }
return $(self.conditional) ;
}
rule non-conditional ( )
{
+ if ! $(self.conditional-initialized)
+ {
+ init-conditional ;
+ }
return $(self.non-conditional) ;
}
@@ -146,6 +127,10 @@ class property-set
#
rule incidental ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.incidental) ;
}
@@ -200,30 +185,19 @@ class property-set
{
if ! $(self.propagated-ps)
{
- self.propagated-ps = [ property-set.create $(self.propagated) ] ;
+ local result ;
+ for local p in $(self.raw)
+ {
+ if propagated in [ feature.attributes $(p:G) ]
+ {
+ result += $(p) ;
+ }
+ }
+ self.propagated-ps = [ property-set.create $(result) ] ;
}
return $(self.propagated-ps) ;
}
- rule link-incompatible ( )
- {
- if ! $(self.link-incompatible-ps)
- {
- self.link-incompatible-ps =
- [ property-set.create $(self.link-incompatible) ] ;
- }
- return $(self.link-incompatible-ps) ;
- }
-
- rule run-actions ( )
- {
- if ! $(self.run)
- {
- self.run = [ property-set.create [ feature.run-actions $(self.raw) ] ] ;
- }
- return $(self.run) ;
- }
-
rule add-defaults ( )
{
if ! $(self.defaults)
@@ -238,7 +212,7 @@ class property-set
{
if ! $(self.as-path)
{
- self.as-path = [ property.as-path $(self.base) ] ;
+ self.as-path = [ property.as-path [ base ] ] ;
}
return $(self.as-path) ;
}
@@ -303,47 +277,81 @@ class property-set
return [ add [ property-set.create $(properties) ] ] ;
}
- rule link-incompatible-with ( ps )
+ # Returns all values of 'feature'.
+ #
+ rule get ( feature )
+ {
+ if ! $(self.map-built)
+ {
+ # For each feature, create a member var and assign all values to it.
+ # Since all regular member vars start with 'self', there will be no
+ # conflicts between names.
+ self.map-built = true ;
+ for local v in $(self.raw)
+ {
+ $(v:G) += $(v:G=) ;
+ }
+ }
+ return $($(feature)) ;
+ }
+
+ # private
+
+ rule init-base ( )
{
- if ! $(.li.$(ps))
+ for local p in $(self.raw)
{
- local li1 = [ $(__name__).link-incompatible ] ;
- local li2 = [ $(ps).link-incompatible ] ;
- if [ set.equal $(li1) : $(li2) ]
+ local att = [ feature.attributes $(p:G) ] ;
+ # A feature can be both incidental and free, in which case we add it
+ # to incidental.
+ if incidental in $(att)
+ {
+ self.incidental += $(p) ;
+ }
+ else if free in $(att)
{
- .li.$(ps) = false ;
+ self.free += $(p) ;
}
else
{
- .li.$(ps) = true ;
+ self.base += $(p) ;
}
}
- if $(.li.$(ps)) = true
- {
- return true ;
- }
- else
+ self.base-initialized = true ;
+ }
+
+ rule init-dependency ( )
+ {
+ for local p in $(self.raw)
{
- return ;
+ local att = [ feature.attributes $(p:G) ] ;
+
+ if dependency in $(att)
+ {
+ self.dependency += $(p) ;
+ }
+ else
+ {
+ self.non-dependency += $(p) ;
+ }
}
+ self.dependency-initialized = true ;
}
- # Returns all values of 'feature'.
- #
- rule get ( feature )
+ rule init-conditional ( )
{
- if ! $(self.map-built)
+ for local p in $(self.raw)
{
- # For each feature, create a member var and assign all values to it.
- # Since all regular member vars start with 'self', there will be no
- # conflicts between names.
- self.map-built = true ;
- for local v in $(self.raw)
+ if [ MATCH (:) : $(p:G=) ]
{
- $(v:G) += $(v:G=) ;
+ self.conditional += $(p) ;
+ }
+ else
+ {
+ self.non-conditional += $(p) ;
}
}
- return $($(feature)) ;
+ self.conditional-initialized = true ;
}
}
diff --git a/tools/build/v2/build/property.py b/tools/build/v2/build/property.py
index c4b13dbcba..c8bbdb29f5 100644
--- a/tools/build/v2/build/property.py
+++ b/tools/build/v2/build/property.py
@@ -63,7 +63,7 @@ class Property(object):
(other._feature, other._value, other._condition))
-def create_from_string(s, allow_condition=False):
+def create_from_string(s, allow_condition=False,allow_missing_value=False):
condition = []
import types
@@ -92,7 +92,7 @@ def create_from_string(s, allow_condition=False):
f = feature.get(feature_name)
value = get_value(s)
- if not value:
+ if not value and not allow_missing_value:
get_manager().errors()("Invalid property '%s' -- no value specified" % s)
diff --git a/tools/build/v2/build/targets.jam b/tools/build/v2/build/targets.jam
index a70532ce73..12e4a5edff 100644
--- a/tools/build/v2/build/targets.jam
+++ b/tools/build/v2/build/targets.jam
@@ -936,7 +936,7 @@ rule common-properties ( build-request requirements )
{
$(key) = [ common-properties2 $(build-request) $(non-free) ] ;
}
- result = [ $($(key)).add-raw $(free) ] ;
+ return [ $($(key)).add-raw $(free) ] ;
}
diff --git a/tools/build/v2/build/targets.py b/tools/build/v2/build/targets.py
index a35612cea0..b8546809a8 100644
--- a/tools/build/v2/build/targets.py
+++ b/tools/build/v2/build/targets.py
@@ -1290,7 +1290,8 @@ class TypedTarget (BasicTarget):
def construct (self, name, source_targets, prop_set):
- r = generators.construct (self.project_, name, self.type_,
+ r = generators.construct (self.project_, os.path.splitext(name)[0],
+ self.type_,
prop_set.add_raw(['<main-target-type>' + self.type_]),
source_targets, True)
diff --git a/tools/build/v2/build/toolset.jam b/tools/build/v2/build/toolset.jam
index f2036d999c..d19be3c0b3 100644
--- a/tools/build/v2/build/toolset.jam
+++ b/tools/build/v2/build/toolset.jam
@@ -15,6 +15,7 @@ import property ;
import regex ;
import sequence ;
import set ;
+import property-set ;
.flag-no = 1 ;
@@ -320,10 +321,82 @@ rule set-target-variables-aux ( rule-or-module : property-set )
return $(result) ;
}
+rule relevant-features ( rule-or-module )
+{
+ local result ;
+ if ! $(.relevant-features.$(rule-or-module))
+ {
+ for local f in $(.$(rule-or-module).flags)
+ {
+ local condition = $(.$(rule-or-module).condition.$(f)) ;
+ local values = $(.$(rule-or-module).values.$(f)) ;
+
+ for local c in $(condition)
+ {
+ for local p in [ feature.split $(c) ]
+ {
+ if $(p:G)
+ {
+ result += $(p:G) ;
+ }
+ else
+ {
+ local temp = [ feature.expand-subfeatures $(p) ] ;
+ result += $(temp:G) ;
+ }
+ }
+ }
+
+ for local v in $(values)
+ {
+ if $(v:G)
+ {
+ result += $(v:G) ;
+ }
+ }
+ }
+
+ # Strip away last dot separated part and recurse.
+ local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
+ if $(next)
+ {
+ result += [ relevant-features $(next[1]) ] ;
+ }
+ result = [ sequence.unique $(result) ] ;
+ if $(result[1]) = ""
+ {
+ result = $(result) ;
+ }
+ .relevant-features.$(rule-or-module) = $(result) ;
+ return $(result) ;
+ }
+ else
+ {
+ return $(.relevant-features.$(rule-or-module)) ;
+ }
+}
+
+rule filter-property-set ( rule-or-module : property-set )
+{
+ if ! $(.filtered.property-set.$(rule-or-module).$(property-set))
+ {
+ local relevant = [ relevant-features $(rule-or-module) ] ;
+ local result ;
+ for local p in [ $(property-set).raw ]
+ {
+ if $(p:G) in $(relevant)
+ {
+ result += $(p) ;
+ }
+ }
+ .filtered.property-set.$(rule-or-module).$(property-set) = [ property-set.create $(result) ] ;
+ }
+ return $(.filtered.property-set.$(rule-or-module).$(property-set)) ;
+}
rule set-target-variables ( rule-or-module targets + : property-set )
{
- properties = [ $(property-set).raw ] ;
+ property-set = [ filter-property-set $(rule-or-module) : $(property-set) ] ;
local key = $(rule-or-module).$(property-set) ;
local settings = $(.stv.$(key)) ;
if ! $(settings)
diff --git a/tools/build/v2/build/toolset.py b/tools/build/v2/build/toolset.py
index b426798784..3665ab872e 100644
--- a/tools/build/v2/build/toolset.py
+++ b/tools/build/v2/build/toolset.py
@@ -68,7 +68,9 @@ def reset ():
reset ()
# FIXME: --ignore-toolset-requirements
-# FIXME: using
+def using(toolset_module, *args):
+ loaded_toolset_module= get_manager().projects().load_module(toolset_module, [os.getcwd()]);
+ loaded_toolset_module.init(*args)
# FIXME push-checking-for-flags-module ....
# FIXME: investigate existing uses of 'hack-hack' parameter
@@ -115,8 +117,8 @@ def flags(rule_or_module, variable_name, condition, values = []):
is specified, then the value of 'feature'
will be added.
"""
- caller = bjam.caller()[:-1]
- if not '.' in rule_or_module and caller.startswith("Jamfile"):
+ caller = bjam.caller()
+ if not '.' in rule_or_module and caller and caller[:-1].startswith("Jamfile"):
# Unqualified rule name, used inside Jamfile. Most likely used with
# 'make' or 'notfile' rules. This prevents setting flags on the entire
# Jamfile module (this will be considered as rule), but who cares?
@@ -142,7 +144,7 @@ def flags(rule_or_module, variable_name, condition, values = []):
transformed = []
for c in condition:
# FIXME: 'split' might be a too raw tool here.
- pl = [property.create_from_string(s) for s in c.split('/')]
+ pl = [property.create_from_string(s,False,True) for s in c.split('/')]
pl = feature.expand_subfeatures(pl);
transformed.append(property_set.create(pl))
condition = transformed
@@ -378,7 +380,6 @@ def add_requirements(requirements):
#if ! $(.ignore-requirements)
#{
- print "XXXX", requirements
__requirements.extend(requirements)
#}
diff --git a/tools/build/v2/build/type.py b/tools/build/v2/build/type.py
index ddb7ba09d2..e815739f40 100644
--- a/tools/build/v2/build/type.py
+++ b/tools/build/v2/build/type.py
@@ -81,7 +81,7 @@ def register (type, suffixes = [], base_type = None):
__types [type] = entry
if base_type:
- __types [base_type]['derived'].append (type)
+ __types.setdefault(base_type, {}).setdefault('derived', []).append(type)
if len (suffixes) > 0:
# Generated targets of 'type' will use the first of 'suffixes'
diff --git a/tools/build/v2/build/version.jam b/tools/build/v2/build/version.jam
index 7626ddda8d..512c9ee31a 100644
--- a/tools/build/v2/build/version.jam
+++ b/tools/build/v2/build/version.jam
@@ -7,7 +7,7 @@ import errors ;
import numbers ;
major = "2011" ;
-minor = "04" ;
+minor = "12" ;
rule boost-build ( )
{
diff --git a/tools/build/v2/build_system.py b/tools/build/v2/build_system.py
index 55d8b806ca..cc1a61b2fb 100644
--- a/tools/build/v2/build_system.py
+++ b/tools/build/v2/build_system.py
@@ -20,6 +20,7 @@ from b2.util.sequence import unique
import b2.build.build_request
from b2.build.errors import ExceptionWithUserContext
import b2.tools.common
+from b2.build.toolset import using
import b2.build.project as project
import b2.build.virtual_target as virtual_target
@@ -290,6 +291,9 @@ def load_configuration_files():
initialize_config_module('user-config')
if not test_config and not legacy_ignore_config:
+ # Here, user_config has value of None if nothing is explicitly
+ # specified, and value of '' if user explicitly does not want
+ # to load any user config.
user_config = None
for a in sys.argv:
m = re.match("--user-config=(.*)$", a)
@@ -297,30 +301,32 @@ def load_configuration_files():
user_config = m.group(1)
break
- if not user_config:
+ if user_config is None:
user_config = os.getenv("BOOST_BUILD_USER_CONFIG")
# Special handling for the case when the OS does not strip the quotes
# around the file name, as is the case when using Cygwin bash.
user_config = b2.util.unquote(user_config)
explicitly_requested = user_config
- if not user_config:
+
+ if user_config is None:
user_config = "user-config.jam"
- if explicitly_requested:
+ if user_config:
+ if explicitly_requested:
- user_config = os.path.abspath(user_config)
+ user_config = os.path.abspath(user_config)
- if debug_config:
- print "notice: Loading explicitly specified user configuration file:"
- print " " + user_config
+ if debug_config:
+ print "notice: Loading explicitly specified user configuration file:"
+ print " " + user_config
- load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True)
+ load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True)
+ else:
+ load_config('user-config', os.path.basename(user_config), user_path)
else:
- load_config('user-config', os.path.basename(user_config), user_path)
-
- elif debug_config:
- print "notice: User configuration file loading explicitly disabled." ;
+ if debug_config:
+ print "notice: User configuration file loading explicitly disabled."
# We look for project-config.jam from "." upward.
# I am not sure this is 100% right decision, we might as well check for
@@ -381,7 +387,10 @@ def process_explicit_toolset_requests():
if debug_config:
print "notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version
- toolset.using(toolset, version)
+ if version is not None:
+ using(toolset, version)
+ else:
+ using(toolset)
else:
@@ -515,7 +524,7 @@ def main_real():
print "warning: For more configuration options, please consult"
print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html"
- toolset.using(dt, dtv)
+ using(dt, dtv)
# Parse command line for targets and properties. Note that this requires
# that all project files already be loaded.
diff --git a/tools/build/v2/doc/src/abstract-target.xml b/tools/build/v2/doc/src/abstract-target.xml
new file mode 100644
index 0000000000..dad53380c4
--- /dev/null
+++ b/tools/build/v2/doc/src/abstract-target.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.abstract-target">
+
+ <title>Class abstract-target</title>
+ <indexterm>
+ <primary>abstract-target</primary>
+ </indexterm>
+
+ <para>
+ Base class for all abstract targets.
+ </para>
+
+<programlisting language="jam">
+class abstract-target {
+ rule <link linkend="bbv2.reference.class.abstract-target.__init__">__init__</link> ( name : project )
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.__init__">generate</link> ( property-set )
+}
+</programlisting>
+
+ <para>
+ Classes derived from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>:
+ <itemizedlist>
+ <listitem>
+ <link linkend="bbv2.reference.class.project-target">project-target</link>
+ </listitem>
+ <listitem>
+ <link linkend="bbv2.reference.class.main-target">main-target</link>
+ </listitem>
+ <listitem>
+ <link linkend="bbv2.reference.class.project-target">basic-target</link>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.abstract-target.__init__">
+ <code language="jam">rule __init__ ( name : project )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem>
+ <para>The name of the target in the Jamfile.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>The <link linkend="bbv2.reference.class.project-target">project</link> to which this target belongs.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.name">
+ <indexterm zone="bbv2.reference.class.abstract-target.name">
+ <primary>name</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule name ( )</code>
+ <para>Returns the name of this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.project">
+ <indexterm zone="bbv2.reference.class.abstract-target.project">
+ <primary>project</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule project ( )</code>
+ <para>Returns the <link linkend="bbv2.reference.class.project-target">project</link> for this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.location">
+ <indexterm zone="bbv2.reference.class.abstract-target.location">
+ <primary>location</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule location ( )</code>
+ <para>Returns the location where the target was declared.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.full-name">
+ <indexterm zone="bbv2.reference.class.abstract-target.full-name">
+ <primary>full-name</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule full-name ( )</code>
+ <para>Returns a user-readable name for this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.generate">
+ <indexterm zone="bbv2.reference.class.abstract-target.generate">
+ <primary>generate</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Generates virtual targets for this abstract target using the specified
+ properties, unless a different value of some feature is required by the
+ target. This is an abstract method which must be overriden by derived
+ classes.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ If <code language="jam">property-set</code> is empty, performs the
+ default build of this target, in a way specific to the derived class.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/basic-target.xml b/tools/build/v2/doc/src/basic-target.xml
new file mode 100644
index 0000000000..ae7c2795c2
--- /dev/null
+++ b/tools/build/v2/doc/src/basic-target.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.basic-target">
+
+ <title>Class basic-target</title>
+ <indexterm>
+ <primary>basic-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class basic-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.basic-target.__init__">__init__</link> ( name : project : sources * : requirements * : default-build * : usage-requirements * )
+ rule <link linkend="bbv2.reference.class.basic-target.generate">generate</link> ( property-set )
+ rule <link linkend="bbv2.reference.class.basic-target.construct">construct</link> ( name : source-targets * : property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ Implements the most standard way of constructing main target alternative from
+ sources. Allows sources to be either files or other main targets and handles
+ generation of those dependency targets.
+ <!-- FIXME: Better description of sources. The sources can be either target
+ references or instances of abstract-target. -->
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.basic-target.__init__">
+ <code language="jam">rule __init__ ( name : project : sources * : requirements * : default-build * : usage-requirements * )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem><para>The name of the target</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.class.project-target">project</link>
+ in which the target is declared.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.basic-target.generate">
+ <indexterm zone="bbv2.reference.class.basic-target.generate">
+ <primary>generate</primary>
+ <secondary>Basic Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Determines final build properties, generates sources, and calls
+ <link linkend="bbv2.reference.class.basic-target.construct">construct</link>.
+ This method should not be overridden.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.basic-target.construct">
+ <indexterm zone="bbv2.reference.class.basic-target.construct">
+ <primary>construct</primary>
+ <secondary>Basic Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule construct ( name : source-targets * : property-set )</code>
+ <para>
+ Constructs virtual targets for this abstract target. Returns a
+ usage-requirements property-set and a list of virtual
+ targets. Should be overriden in derived classes.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/catalog.xml b/tools/build/v2/doc/src/catalog.xml
deleted file mode 100644
index 26e16145d3..0000000000
--- a/tools/build/v2/doc/src/catalog.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE catalog
- PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
- "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
-<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
- <rewriteURI uriStartString="http://www.boost.org/tools/boostbook/dtd/" rewritePrefix="file:///home/ccurrie/src/boost/tools/boostbook/dtd//"/>
- <rewriteURI uriStartString="http://docbook.sourceforge.net/release/xsl/current/" rewritePrefix="file:///shared/ccurrie/share/sgml/docbook/docbook-xsl-1.64.1/"/>
- <rewriteURI uriStartString="http://www.oasis-open.org/docbook/xml/4.2/" rewritePrefix="file:///shared/ccurrie/share/sgml/docbook/docbook-dtd-4.2/"/>
-</catalog>
diff --git a/tools/build/v2/doc/src/extending.xml b/tools/build/v2/doc/src/extending.xml
index 3d0fda569d..43ef0bbb37 100644
--- a/tools/build/v2/doc/src/extending.xml
+++ b/tools/build/v2/doc/src/extending.xml
@@ -76,17 +76,20 @@
in Jamfile, such as metatarget kind, name, sources and properties,
and can be called with specific properties to generate concrete
targets. At the code level it is represented by an instance of
- class derived from <classname>abstract-target</classname>.
+ class derived from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>.
<footnote><para>This name is historic, and will be eventuall changed to
<code>metatarget</code></para></footnote>
</para>
- <para>The <methodname>generate</methodname> method takes the build properties
- (as an instance of the <classname>property-set</classname> class) and returns
+ <para>The <link linkend="bbv2.reference.class.abstract-target.generate">generate</link>
+ method takes the build properties
+ (as an instance of the <link linkend="bbv2.reference.class.property-set">
+ property-set</link> class) and returns
a list containing:</para>
<itemizedlist>
<listitem><para>As front element&mdash;Usage-requirements from this invocation
- (an instance of <classname>property-set</classname>)</para></listitem>
+ (an instance of <link linkend="bbv2.reference.class.property-set">
+ property-set</link>)</para></listitem>
<listitem><para>As subsequent elements&mdash;created concrete targets (
instances of the <classname>virtual-target</classname> class.)</para></listitem>
</itemizedlist>
@@ -96,47 +99,52 @@
<code>targets.generate-from-reference</code> function can both
lookup and generate a metatarget.</para>
- <para>The <classname>abstract-target</classname> class has three immediate
- derived classes:</para>
+ <para>The <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ class has three immediate derived classes:</para>
<itemizedlist>
- <listitem><para><classname>project-target</classname> that
+ <listitem><para><link linkend="bbv2.reference.class.project-target">project-target</link> that
corresponds to a project and is not intended for further
- subclassing. The <methodname>generate</methodname> method of this
+ subclassing. The <link linkend="bbv2.reference.class.project-target.generate">
+ generate</link> method of this
class builds all targets in the project that are not marked as
explicit.</para></listitem>
- <listitem><para><classname>main-target</classname> corresponds to a target in a project
+ <listitem><para><link linkend="bbv2.reference.class.main-target">main-target</link>
+ corresponds to a target in a project
and contains one or more target alternatives. This class also should not be
- subclassed. The <methodname>generate</methodname> method of this class selects
- an alternative to build, and calls the <methodname>generate</methodname> method of that
- alternative.</para></listitem>
+ subclassed. The <link linkend="bbv2.reference.class.main-target.generate">generate</link>
+ method of this class selects an alternative to build, and calls the
+ <link linkend="bbv2.reference.class.basic-target.generate">generate</link>
+ method of that alternative.</para></listitem>
- <listitem><para><classname>basic-target</classname> corresponds to a
- specific target alternative. This is base class, with a number of
- derived classes. The <methodname>generate</methodname> method
+ <listitem><para><link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ corresponds to a specific target alternative. This is base class,
+ with a number of derived classes. The
+ <link linkend="bbv2.reference.class.basic-target.generate">generate</link> method
processes the target requirements and requested build properties to
determine final properties for the target, builds all sources, and
- finally calls the abstract <classname>construct</classname> method with the list
- of source virtual targets, and the final properties.
+ finally calls the abstract
+ <link linkend="bbv2.reference.class.basic-target.construct">construct</link>
+ method with the list of source virtual targets, and the final properties.
</para></listitem>
</itemizedlist>
- <para>The instances of the <classname>project-target</classname> and
- <classname>main-target</classname> classes are created
+ <para>The instances of the <link linkend="bbv2.reference.class.project-target">project-target</link> and
+ <link linkend="bbv2.reference.class.main-target">main-target</link> classes are created
implicitly&mdash;when loading a new Jamfiles, or when a new target
alternative with as-yet unknown name is created. The instances of the
- classes derived from <classname>basic-target</classname> are typically
- created when Jamfile calls a <firstterm>metatarget rule</firstterm>,
+ classes derived from <link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ are typically created when Jamfile calls a <firstterm>metatarget rule</firstterm>,
such as such as <code>exe</code>.
</para>
<para>It it permissible to create a custom class derived from
- <classname>basic-target</classname> and create new metatarget rule
+ <link linkend="bbv2.reference.class.basic-target">basic-target</link> and create new metatarget rule
that creates instance of such target. However, in the majority
- of cases, a specific subclass of <classname>basic-target</classname>&mdash;
- <classname>typed-target</classname> is used. That class is associated
+ of cases, a specific subclass of <link linkend="bbv2.reference.class.basic-target">basic-target</link>&mdash;
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link> is used. That class is associated
with a <firstterm>type</firstterm> and relays to <firstterm>generators</firstterm>
to construct concrete targets of that type. This process will be explained below.
When a new type is declared, a new metatarget rule is automatically defined.
@@ -153,8 +161,8 @@
subclass is <classname>file-target</classname>. A file target is associated
with an action that creates it&mdash; an instance of the <classname>action</classname>
class. The action, in turn, hold a list of source targets. It also holds the
- <classname>property-set</classname> instance with the build properties that
- should be used for the action.</para>
+ <link linkend="bbv2.reference.class.property-set">property-set</link>
+ instance with the build properties that should be used for the action.</para>
<para>Here's an example of creating a target from another target, <code>source</code></para>
<programlisting>
@@ -200,11 +208,12 @@ return [ sequence.transform virtual-target.register : $(targets) ] ;
fact, Boost.Build defines concept of target type and
<indexterm><primary>generators</primary></indexterm>
<firstterm>generators</firstterm>, and has special metatarget class
- <classname>typed-target</classname>. Target type is merely an
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>. Target type is merely an
identifier. It is associated with a set of file extensions that
correspond to that type. Generator is an abstraction of a tool. It advertises
the types it produces and, if called with a set of input target, tries to construct
- output targets of the advertised types. Finally, <classname>typed-target</classname>
+ output targets of the advertised types. Finally,
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>
is associated with specific target type, and relays the generator (or generators)
for that type.
</para>
@@ -393,7 +402,7 @@ import type ;
type.register VERBATIM : verbatim ;
</programlisting>
- <para>The first parameter to <functionname>type.register</functionname> gives
+ <para>The first parameter to <link linkend="bbv2.reference.modules.type.register">type.register</link> gives
the name of the declared type. By convention, it's uppercase. The second
parameter is the suffix for files of this type. So, if Boost.Build sees
<filename>code.verbatim</filename> in a list of sources, it knows that it's of
@@ -1031,8 +1040,8 @@ feature.compose &lt;parallelism&gt;fake : &lt;library&gt;/mpi//fake/&lt;parallel
<section id="bbv2.extending.rules">
<title>Main target rules</title>
<para>
- A main target rule (e.g “<functionname>exe</functionname>”
- Or “<functionname>lib</functionname>”) creates a top-level target. It's quite likely that you'll want to declare your own and
+ A main target rule (e.g “<link linkend="bbv2.tasks.programs">exe</link>”
+ Or “<link linkend="bbv2.tasks.libraries">lib</link>”) creates a top-level target. It's quite likely that you'll want to declare your own and
there are two ways to do that.
<!-- Why did "that" get changed to "this" above? -->
</para>
diff --git a/tools/build/v2/doc/src/faq.xml b/tools/build/v2/doc/src/faq.xml
index 551e22e25b..a648a3761c 100644
--- a/tools/build/v2/doc/src/faq.xml
+++ b/tools/build/v2/doc/src/faq.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" standalone="yes"?>
-<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<chapter id="bbv2.faq">
<title>Frequently Asked Questions</title>
- <section>
+ <section id="bbv2.faq.featurevalue">
<title>
How do I get the current value of feature in Jamfile?
</title>
@@ -13,7 +13,7 @@
<para>
This is not possible, since Jamfile does not have "current" value of any
feature, be it toolset, build variant or anything else. For a single
- invocation of <filename>bjam</filename>, any given main target can be
+ run of Boost.Build, any given main target can be
built with several property sets. For example, user can request two build
variants on the command line. Or one library is built as shared when used
from one application, and as static when used from another. Each Jamfile
@@ -41,7 +41,7 @@
</itemizedlist>
</section>
- <section>
+ <section id="bbv2.faq.duplicate">
<title>
I am getting a "Duplicate name of actual target" error. What does that
mean?
@@ -174,7 +174,7 @@ exe a : a.cpp : &lt;include&gt;$(SOME_LIBRARY_PATH) ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.proporder">
<title>
How to control properties order?
</title>
@@ -203,7 +203,7 @@ exe a : a.cpp : &lt;include&gt;a&amp;&amp;b ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.liborder">
<title>
How to control the library linking order on Unix?
</title>
@@ -257,7 +257,7 @@ local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.projectroot">
<title>
How to get the project root (a.k.a. Jamroot) location?
</title>
@@ -272,7 +272,7 @@ path-constant TOP : . ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.flags">
<title>
How to change compilation flags for one file?
</title>
diff --git a/tools/build/v2/doc/src/howto.xml b/tools/build/v2/doc/src/howto.xml
index bd128a3214..de17a286a8 100644
--- a/tools/build/v2/doc/src/howto.xml
+++ b/tools/build/v2/doc/src/howto.xml
@@ -28,7 +28,7 @@
<para>
If you have questions, please post them to our mailing list (<ulink
url="http://boost.org/more/mailing_lists.htm#jamboost"/>). The mailing list is
- also mirrowed to newsgroup <ulink url="news://news.gmane.org/gmane.comp.lib.boost.build"/>.
+ also mirrored to the newsgroup <ulink url="news://news.gmane.org/gmane.comp.lib.boost.build"/>.
</para>
</chapter>
diff --git a/tools/build/v2/doc/src/install.xml b/tools/build/v2/doc/src/install.xml
index afae46aa15..545f786695 100644
--- a/tools/build/v2/doc/src/install.xml
+++ b/tools/build/v2/doc/src/install.xml
@@ -29,7 +29,7 @@
<listitem>
<simpara>
Run
- <screen>./bjam install --prefix=<replaceable>PREFIX</replaceable></screen>
+ <screen>./b2 install --prefix=<replaceable>PREFIX</replaceable></screen>
where <replaceable>PREFIX</replaceable> is a directory where you
want Boost.Build to be installed.
</simpara>
@@ -43,15 +43,15 @@
</listitem>
</orderedlist>
- <para>If you are not using Boost.Build package, but rather the version
+ <para>If you are not using a Boost.Build package, but rather the version
bundled with the Boost C++ Libraries, the above commands should be run
in the <filename>tools/build/v2</filename> directory.</para>
<para>
- Now that Boost.Build is installed, you can try some of examples. Copy
+ Now that Boost.Build is installed, you can try some of the examples. Copy
<filename><replaceable>PREFIX</replaceable>/share/boost-build/examples/hello</filename>
to a different directory, then change to that directory and run:
-<screen><filename><replaceable>PREFIX</replaceable>/bin/bjam</filename></screen>
+<screen><filename><replaceable>PREFIX</replaceable>/bin/b2</filename></screen>
A simple executable should be built.
</para>
diff --git a/tools/build/v2/doc/src/main-target.xml b/tools/build/v2/doc/src/main-target.xml
new file mode 100644
index 0000000000..84afac14f8
--- /dev/null
+++ b/tools/build/v2/doc/src/main-target.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.main-target">
+
+ <title>Class main-target</title>
+ <indexterm>
+ <primary>main-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class main-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.main-target.generate">generate</link> ( property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ A <link linkend="bbv2.reference.class.main-target">main-target</link>
+ represents a named top-level target in a Jamfile.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.main-target.generate">
+ <indexterm zone="bbv2.reference.class.main-target.generate">
+ <primary>generate</primary>
+ <secondary>Main Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Select an alternative for this main target, by finding all alternatives
+ whose requirements are satisfied by <literal>property-set</literal> and
+ picking the one with the longest requirements set. Returns the result
+ of calling <link linkend="bbv2.reference.class.basic-target.generate">generate</link>
+ on that alternative.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/overview.xml b/tools/build/v2/doc/src/overview.xml
index 048898867e..90b7c27227 100644
--- a/tools/build/v2/doc/src/overview.xml
+++ b/tools/build/v2/doc/src/overview.xml
@@ -17,20 +17,20 @@
Boost.Build actually consists of two parts - Boost.Jam, a build engine
with its own interpreted language, and Boost.Build itself, implemented in
Boost.Jam's language. The chain of events when you type
- <command>bjam</command> on the command line is as follows:
+ <command>b2</command> on the command line is as follows:
<orderedlist>
<listitem>
<para>
- Boost.Jam tries to find Boost.Build and loads the top-level module.
- The exact process is described in <xref linkend=
+ The Boost.Build executable tries to find Boost.Build modules and
+ loads the top-level module. The exact process is described in <xref linkend=
"bbv2.reference.init"/>
</para>
</listitem>
<listitem>
<para>
The top-level module loads user-defined configuration files,
- <filename>user-config.jam</filename> and <filename>site-config.jam
- </filename>, which define available toolsets.
+ <filename>user-config.jam</filename> and
+ <filename>site-config.jam</filename>, which define available toolsets.
</para>
</listitem>
<listitem>
@@ -97,8 +97,8 @@
a.o: a.c
g++ -o a.o -g a.c
</programlisting>
- This is rather low-level description mechanism and it's hard to adjust commands, options,
- and sets of created targets depending on the used compiler and operating system.
+ This is a rather low-level description mechanism and it's hard to adjust commands, options,
+ and sets of created targets depending on the compiler and operating system used.
</para>
<para>
@@ -107,20 +107,20 @@ a.o: a.c
<programlisting>
add_program ("a", "a.c")
</programlisting>
- This is a function call that creates targets necessary to create executable file
- from source file <filename>a.c</filename>. Depending on configured properties,
- different commands line may be used. However, <code>add_program</code> is higher-level,
- but rather thin level. All targets are created immediately when build description
+ This is a function call that creates the targets necessary to create a executable file
+ from the source file <filename>a.c</filename>. Depending on configured properties,
+ different command lines may be used. However, <code>add_program</code> is higher-level,
+ but rather thin level. All targets are created immediately when the build description
is parsed, which makes it impossible to perform multi-variant builds. Often, change
- in any build property requires complete reconfiguration of the build tree.
+ in any build property requires a complete reconfiguration of the build tree.
</para>
<para>
- In order to support true multivariant builds, Boost.Build introduces the concept of
+ In order to support true multivariant builds, Boost.Build introduces the concept of a
<indexterm> <primary>metatarget</primary> <secondary>definition</secondary></indexterm>
<indexterm> <primary>main target</primary> <see>metataget</see> </indexterm>
- <firstterm>metatarget</firstterm>&mdash;object that is created when build description
- is parsed and can be later called with specific build properties to generate
+ <firstterm>metatarget</firstterm>&mdash;an object that is created when the build description
+ is parsed and can be called later with specific build properties to generate
actual targets.
</para>
@@ -130,11 +130,11 @@ add_program ("a", "a.c")
exe a : a.cpp ;
</programlisting>
When this declaration is parsed, Boost.Build creates a metatarget, but does not
- yet decides what files must be created, or what commands must be used. After
- all build files are parsed, Boost.Build considers properties requested on the
+ yet decide what files must be created, or what commands must be used. After
+ all build files are parsed, Boost.Build considers the properties requested on the
command line. Supposed you have invoked Boost.Build with:
<screen>
-bjam toolset=gcc toolset=msvc
+b2 toolset=gcc toolset=msvc
</screen>
In that case, the metatarget will be called twice, once with <code>toolset=gcc</code>
and once with <code>toolset=msvc</code>. Both invocations will produce concrete
@@ -142,9 +142,9 @@ bjam toolset=gcc toolset=msvc
</para>
<para>
- Another key concept is
+ Another key concept is
<indexterm><primary>property</primary><secondary>definition</secondary></indexterm>
- <firstterm>build property</firstterm>. Build property is a variable
+ <firstterm>build property</firstterm>. A build property is a variable
that affects the build process. It can be specified on the command line, and is
passed when calling a metatarget. While all build tools have a similar mechanism,
Boost.Build differs by requiring that all build properties are declared in advance,
@@ -158,12 +158,12 @@ bjam toolset=gcc toolset=msvc
"top-level" metatargets are called with the properties specified on the command line.
Each metatarget can elect to augment or override some properties (in particular,
using the requirements mechanism, see <xref linkend="bbv2.overview.targets.requirements"/>).
- Then, the dependency metatargets are called with modified properties and produce
- concrete targets that are then used in build process. Of course, dependency metatargets
+ Then, the dependency metatargets are called with the modified properties and produce
+ concrete targets that are then used in the build process. Of course, dependency metatargets
maybe in turn modify build properties and have dependencies of their own.
</para>
- <para>For more in-depth treatment of the requirements and concepts, you may refer
+ <para>For a more in-depth treatment of the requirements and concepts, you may refer
to <ulink url="http://syrcose.ispras.ru/2009/files/04_paper.pdf">SYRCoSE 2009 Boost.Build article</ulink>.
</para>
@@ -173,8 +173,8 @@ bjam toolset=gcc toolset=msvc
<title>Boost.Jam Language</title>
<para>
- This section will describe the basics of the Boost.Jam language&#x2014;
- just enough for writing Jamfiles. For more information, please see the
+ This section will describe the basics of the Boost.Jam language&#x2014;just
+ enough for writing Jamfiles. For more information, please see the
<link linkend="bbv2.jam">Boost.Jam</link> documentation.
</para>
@@ -182,8 +182,8 @@ bjam toolset=gcc toolset=msvc
<link linkend="bbv2.jam">Boost.Jam</link> has an interpreted, procedural
language. On the lowest level, a <link linkend="bbv2.jam">Boost.Jam
</link> program consists of variables and <indexterm><primary>rule
- </primary></indexterm> <firstterm>rules</firstterm> (Jam term for
- function). They are grouped into modules&#x2014;there is one global
+ </primary></indexterm> <firstterm>rules</firstterm> (the Jam term for
+ functions). They are grouped into modules&#x2014;there is one global
module and a number of named modules. Besides that, a <link linkend=
"bbv2.jam">Boost.Jam</link> program contains classes and class
instances.
@@ -325,7 +325,7 @@ rule test ( )
import <replaceable>module</replaceable> ;
import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;
</programlisting>
- The first form imports the specified bjam module. All rules from that
+ The first form imports the specified module. All rules from that
module are made available using the qualified name: <code><replaceable>
module</replaceable>.<replaceable>rule</replaceable></code>. The second
form imports the specified rules only, and they can be called using
@@ -333,8 +333,8 @@ import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;
</para>
<para id="bbv2.overview.jam_language.actions">
- Sometimes, you'd need to specify the actual command lines to be used
- when creating targets. In jam language, you use named actions to do
+ Sometimes, you need to specify the actual command lines to be used
+ when creating targets. In the jam language, you use named actions to do
this. For example:
<programlisting>
actions create-file-from-another
@@ -350,8 +350,8 @@ actions create-file-from-another
</para>
<para>
- To flexibly adjust the command line, you can define a rule with the same
- name as the action and taking three parameters -- targets, sources and
+ To adjust the command line flexibly, you can define a rule with the same
+ name as the action and taking three parameters&mdash;targets, sources and
properties. For example:
<programlisting>
rule create-file-from-another ( targets * : sources * : properties * )
@@ -366,8 +366,8 @@ actions create-file-from-another
create-file-from-another $(OPTIONS) $(&lt;) $(&gt;)
}
</programlisting>
- In this example, the rule checks if certain build property is specified.
- If so, it sets variable <varname>OPIONS</varname> that is then used
+ In this example, the rule checks if a certain build property is specified.
+ If so, it sets the variable <varname>OPIONS</varname> that is then used
inside the action. Note that the variables set "on a target" will be
visible only inside actions building that target, not globally. Were
they set globally, using variable named <varname>OPTIONS</varname> in
@@ -375,7 +375,7 @@ actions create-file-from-another
</para>
<para>
- More details can be found in Jam reference, <xref
+ More details can be found in the Jam reference, <xref
linkend="jam.language.rules"/>.
</para>
</section>
@@ -386,9 +386,9 @@ actions create-file-from-another
<para>
On startup, Boost.Build searches and reads two configuration files:
<filename>site-config.jam</filename> and <filename>user-config.jam</filename>.
- The first one is usually installed and maintained by system administrator, and
- the second is for user to modify. You can edit the one in the top-level
- directory of Boost.Build installation or create a copy in your home
+ The first one is usually installed and maintained by a system administrator, and
+ the second is for the user to modify. You can edit the one in the top-level
+ directory of your Boost.Build installation or create a copy in your home
directory and edit the copy. The following table explains where both files
are searched.
</para>
@@ -453,7 +453,7 @@ actions create-file-from-another
</tip>
<para>
- Usually, <filename>user-config.jam</filename> just defines available compilers
+ Usually, <filename>user-config.jam</filename> just defines the available compilers
and other tools (see <xref linkend="bbv2.recipies.site-config"/> for more advanced
usage). A tool is configured using the following syntax:
</para>
@@ -462,7 +462,7 @@ actions create-file-from-another
using <replaceable>tool-name</replaceable> : ... ;
</programlisting>
<para>
- The <functionname>using</functionname> rule is given a name of tool, and
+ The <code language="jam">using</code> rule is given the name of tool, and
will make that tool available to Boost.Build. For example,
<programlisting>
using gcc ;
@@ -476,9 +476,9 @@ using gcc ;
</para>
<para>
- For all the C++ compiler toolsets Boost.Build supports
+ For all the C++ compiler toolsets that Boost.Build supports
out-of-the-box, the list of parameters to
- <functionname>using</functionname> is the same: <parameter
+ <code language="jam">using</code> is the same: <parameter
class="function">toolset-name</parameter>, <parameter
class="function">version</parameter>, <parameter
class="function">invocation-command</parameter>, and <parameter
@@ -509,8 +509,8 @@ using msvc : : "Z:/Programs/Microsoft Visual Studio/vc98/bin/cl" ;
<para>
Some Boost.Build toolsets will use that path to take additional actions
required before invoking the compiler, such as calling vendor-supplied
- scripts to set up its required environment variables. When compiler
- executables for C and C++ are different, path to the C++ compiler
+ scripts to set up its required environment variables. When the compiler
+ executables for C and C++ are different, the path to the C++ compiler
executable must be specified. The command can
be any command allowed by the operating system. For example:
<programlisting>
@@ -521,13 +521,13 @@ using msvc : : echo Compiling &#x26;&#x26; foo/bar/baz/cl ;
<para>
To configure several versions of a toolset, simply invoke the
- <functionname>using</functionname> rule multiple times:
+ <code language="jam">using</code> rule multiple times:
<programlisting>
using gcc : 3.3 ;
using gcc : 3.4 : g++-3.4 ;
using gcc : 3.2 : g++-3.2 ;
</programlisting>
- Note that in the first call to <functionname>using</functionname>, the
+ Note that in the first call to <code language="jam">using</code>, the
compiler found in the <envar>PATH</envar> will be used, and there is no
need to explicitly specify the command.
</para>
@@ -581,13 +581,13 @@ using gcc : 3.4 : g++-3.4 ;
<section id="bbv2.overview.invocation">
<title>Invocation</title>
- <para>To invoke Boost.Build, type <command>bjam</command> on the command line. Three kinds
+ <para>To invoke Boost.Build, type <command>b2</command> on the command line. Three kinds
of command-line tokens are accepted, in any order:</para>
<variablelist>
<varlistentry>
<term>options</term>
- <listitem><para>Options start with either dash, or two dashes. The standard options
+ <listitem><para>Options start with either one or two dashes. The standard options
are listed below, and each project may add additional options</para></listitem>
</varlistentry>
@@ -595,8 +595,8 @@ using gcc : 3.4 : g++-3.4 ;
<term>properties</term>
<listitem><para>Properties specify details of what you want to build (e.g. debug
- or release variant). Syntactically, all command line tokens with equal sign in them
- are considered to specify properties. In the simplest form, property looks like
+ or release variant). Syntactically, all command line tokens with an equal sign in them
+ are considered to specify properties. In the simplest form, a property looks like
<command><replaceable>feature</replaceable>=<replaceable>value</replaceable></command>
</para></listitem>
</varlistentry>
@@ -613,22 +613,22 @@ using gcc : 3.4 : g++-3.4 ;
<section id="bbv2.overview.invocation.examples">
<title>Examples</title>
- <para>To build all targets defined in Jamfile in the current directory with default properties, run:
+ <para>To build all targets defined in the Jamfile in the current directory with the default properties, run:
<screen>
-bjam
+b2
</screen>
</para>
<para>To build specific targets, specify them on the command line:
<screen>
-bjam lib1 subproject//lib2
+b2 lib1 subproject//lib2
</screen>
</para>
<para>To request a certain value for some property, add <literal>
<replaceable>property</replaceable>=<replaceable>value</replaceable></literal> to the command line:
<screen>
-bjam toolset=gcc variant=debug optimization=space
+b2 toolset=gcc variant=debug optimization=space
</screen>
</para>
</section>
@@ -673,8 +673,8 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--build-dir</option></term>
<listitem>
- <para>Changes build directories for all project roots being built. When
- this option is specified, all Jamroot files should declare project name.
+ <para>Changes the build directories for all project roots being built. When
+ this option is specified, all Jamroot files must declare a project name.
The build directory for the project root will be computed by concatanating
the value of the <option>--build-dir</option> option, the project name
specified in Jamroot, and the build dir specified in Jamroot
@@ -690,7 +690,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--version</option></term>
<listitem>
- <para>Prints information on Boost.Build and Boost.Jam
+ <para>Prints information on the Boost.Build and Boost.Jam
versions.
</para>
</listitem>
@@ -713,7 +713,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>-q</option></term>
<listitem>
- <para>Stop at first error, as opposed to continuing to build targets
+ <para>Stop at the first error, as opposed to continuing to build targets
that don't depend on the failed ones.</para>
</listitem>
</varlistentry>
@@ -728,7 +728,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--debug-configuration</option></term>
<listitem>
- <para>Produces debug information about loading of Boost.Build
+ <para>Produces debug information about the loading of Boost.Build
and toolset files.</para>
</listitem>
</varlistentry>
@@ -744,7 +744,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--debug-generators</option></term>
<listitem>
- <para>Produces debug output from generator search process.
+ <para>Produces debug output from the generator search process.
Useful for debugging custom generators.
</para>
</listitem>
@@ -753,8 +753,8 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--ignore-config</option></term>
<listitem>
- <para>Do not load <literal>site-config.jam</literal> and
- <literal>user-config.jam</literal> configuration files.
+ <para>Do not load <literal>site-config.jam</literal> or
+ <literal>user-config.jam</literal>.
</para>
</listitem>
</varlistentry>
@@ -937,11 +937,12 @@ bjam toolset=gcc variant=debug optimization=space
</tgroup>
</table>
- If you have more than one version of a given C++ toolset (e.g. configured in
+ <para>If you have more than one version of a given C++ toolset (e.g. configured in
<filename>user-config.jam</filename>, or autodetected, as happens with msvc), you can
request the specific version by passing
<code><replaceable>toolset</replaceable>-<replaceable>version</replaceable></code> as
the value of the <code>toolset</code> feature, for example <code>toolset=msvc-8.0</code>.
+ </para>
<para>
@@ -951,21 +952,21 @@ bjam toolset=gcc variant=debug optimization=space
once for each specified value of a feature. For example, if you use
</para>
<screen>
-bjam link=static link=shared threading=single threading=multi
+b2 link=static link=shared threading=single threading=multi
</screen>
<para>
Then a total of 4 builds will be performed. For convenience,
instead of specifying all requested values of a feature in separate command line elements,
- you can separate the values with commands, for example:
+ you can separate the values with commas, for example:
</para>
<screen>
-bjam link=static,shared threading=single,multi
+b2 link=static,shared threading=single,multi
</screen>
<para>
- The comma has special meaning only if the feature has a fixed set of values, so
+ The comma has this special meaning only if the feature has a fixed set of values, so
</para>
<screen>
-bjam include=static,shared
+b2 include=static,shared
</screen>
<para>is not treated specially.</para>
@@ -1068,7 +1069,7 @@ rule <replaceable>rule-name</replaceable> (
</para>
<para>The actual requirements for a target are obtained by refining
- requirements of the project where a target is declared with the
+ the requirements of the project where the target is declared with the
explicitly specified requirements. The same is true for
usage-requirements. More details can be found in
<xref linkend="bbv2.reference.variants.proprefine"/>
@@ -1108,7 +1109,8 @@ obj test.debug : test.cpp : &lt;variant&gt;debug ;
files. Sometimes, you'll want to automatically construct the
list of source files rather than having to spell it out
manually, in which case you can use the
- <functionname>glob</functionname> rule. Here are two examples:</para>
+ <link linkend="bbv2.reference.rules.glob">glob</link> rule.
+ Here are two examples:</para>
<programlisting>
exe a : a.cpp ; # a.cpp is the only source file
exe b : [ glob *.cpp ] ; # all .cpp files in this directory are sources
@@ -1158,7 +1160,7 @@ exe c : c.cpp /boost/program_options//program_options ;
<programlisting>
exe hello : hello.cpp : &lt;include&gt;/opt/boost &lt;define&gt;MY_DEBUG ;
</programlisting>
- There is a number of other features, listed in
+ There are a number of other features, listed in
<xref linkend="bbv2.overview.builtins.features"/>. For example if
a library can only be built statically, or a file can't be compiled
with optimization due to a compiler bug, one can use
@@ -1221,13 +1223,13 @@ rule my-rule ( properties * )
<para>Requirements explicitly specified for a target are usually
combined with the requirements specified for the containing project. You
- can cause a target to completely ignore specific project's requirement
- using the syntax by adding a minus sign before a property, for example:
+ can cause a target to completely ignore a specific project requirement
+ using the syntax by adding a minus sign before the property, for example:
<programlisting>
exe main : main.cpp : <emphasis role="bold">-&lt;define&gt;UNNECESSARY_DEFINE</emphasis> ;
</programlisting>
- This syntax is the only way to ignore free properties from a parent,
- such as defines. It can be also useful for ordinary properties. Consider
+ This syntax is the only way to ignore free properties, such as defines,
+ from a parent. It can be also useful for ordinary properties. Consider
this example:
<programlisting>
project test : requirements &lt;threading&gt;multi ;
@@ -1235,12 +1237,12 @@ exe test1 : test1.cpp ;
exe test2 : test2.cpp : &lt;threading&gt;single ;
exe test3 : test3.cpp : -&lt;threading&gt;multi ;
</programlisting>
- Here, <code>test1</code> inherits project requirements and will always
+ Here, <code>test1</code> inherits the project requirements and will always
be built in multi-threaded mode. The <code>test2</code> target
- <emphasis>overrides</emphasis> project's requirements and will
+ <emphasis>overrides</emphasis> the project's requirements and will
always be built in single-threaded mode. In contrast, the
<code>test3</code> target <emphasis>removes</emphasis> a property
- from project requirements and will be built either in single-threaded or
+ from the project requirements and will be built either in single-threaded or
multi-threaded mode depending on which variant is requested by the
user.</para>
@@ -1260,7 +1262,7 @@ exe hello : hello.cpp : : &lt;threading&gt;multi ;
</programlisting>
would build a multi-threaded target unless the user
explicitly requests a single-threaded version. The difference between
- requirements and default-build is that requirements cannot be
+ the requirements and the default-build is that the requirements cannot be
overridden in any way.
</para>
</section>
@@ -1276,7 +1278,7 @@ exe hello : hello.cpp : : &lt;threading&gt;multi ;
it. We can express this situation using <firstterm>target
alternatives</firstterm>:
<programlisting>
-lib demangler : dummy_demangler.cpp ; # alternative 1
+lib demangler : dummy_demangler.cpp ; # alternative 1
lib demangler : demangler_gcc.cpp : &lt;toolset&gt;gcc ; # alternative 2
lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3
</programlisting>
@@ -1299,13 +1301,13 @@ exe hello : hello.cpp
optimization. When referring to an inline main target, its declared
name must be prefixed by its parent target's name and two dots. In
the example above, to build only helpers, one should run
- <code>bjam hello..helpers</code>.
+ <code>b2 hello..helpers</code>.
</para>
<para>When no target is requested on the command line, all targets in the
current project will be built. If a target should be built only by
explicit request, this can be expressed by the
- <functionname>explicit</functionname> rule:
+ <link linkend="bbv2.reference.rules.explicit">explicit</link> rule:
<programlisting>
explicit install_programs ;</programlisting>
</para>
@@ -1325,7 +1327,7 @@ explicit install_programs ;</programlisting>
</para>
<para>Projects are named using the
- <functionname>project</functionname> rule, which has the
+ <code language="jam">project</code> rule, which has the
following syntax:
<programlisting>
project <replaceable>id</replaceable> : <replaceable>attributes</replaceable> ;
@@ -1388,7 +1390,7 @@ project tennis
<entry>Default value</entry>
- <entry>Handling by the <functionname>project</functionname>
+ <entry>Handling by the <code language="jam">project</code>
rule</entry>
</row>
@@ -1541,7 +1543,7 @@ project tennis
The command line specifies which targets to build and with which
properties. For example:
<programlisting>
-bjam app1 lib1//lib1 toolset=gcc variant=debug optimization=full
+b2 app1 lib1//lib1 toolset=gcc variant=debug optimization=full
</programlisting>
would build two targets, "app1" and "lib1//lib1" with the specified
properties. You can refer to any targets, using
@@ -1549,7 +1551,7 @@ bjam app1 lib1//lib1 toolset=gcc variant=debug optimization=full
properties. Some of the properties are very common, and for them the name
of the property can be omitted. For example, the above can be written as:
<programlisting>
-bjam app1 lib1//lib1 gcc debug optimization=full
+b2 app1 lib1//lib1 gcc debug optimization=full
</programlisting>
The complete syntax, which has some additional shortcuts, is
described in <xref linkend="bbv2.overview.invocation"/>.
@@ -1640,7 +1642,7 @@ bjam app1 lib1//lib1 gcc debug optimization=full
<section><title>Building a Project</title>
<para>Often, a user builds a complete project, not just one main
- target. In fact, invoking <command>bjam</command> without
+ target. In fact, invoking <command>b2</command> without
arguments
<!-- do you know the difference between parameters and
arguments? I only learned this year -->
diff --git a/tools/build/v2/doc/src/path.xml b/tools/build/v2/doc/src/path.xml
new file mode 100644
index 0000000000..31f47a8dca
--- /dev/null
+++ b/tools/build/v2/doc/src/path.xml
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.modules.path">
+
+ <title>path</title>
+ <indexterm>
+ <primary>path</primary>
+ </indexterm>
+
+ <para>
+ Performs various path manipulations. Paths are always in a 'normalized'
+ representation. In it, a path may be either:
+
+ <itemizedlist>
+ <listitem><para><code>'.'</code>, or</para></listitem>
+ <listitem>
+ <para>
+ <code>['/'] [ ( '..' '/' )* (token '/')* token ]</code>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ In plain english, a path can be rooted, <code>'..'</code>
+ elements are allowed only at the beginning, and it never
+ ends in slash, except for the path consisting of slash only.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.path.make">
+ <indexterm zone="bbv2.reference.modules.path.make">
+ <primary>make</primary>
+ <secondary>path</secondary>
+ </indexterm>
+ <code language="jam">rule make ( native )</code>
+ <para>Converts the native path into normalized form.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.native">
+ <indexterm zone="bbv2.reference.modules.path.native">
+ <primary>native</primary>
+ </indexterm>
+ <code language="jam">rule native ( path )</code>
+ <para>Builds the native representation of the path.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.is-rooted">
+ <indexterm zone="bbv2.reference.modules.path.is-rooted">
+ <primary>is-rooted</primary>
+ </indexterm>
+ <code language="jam">rule is-rooted ( path )</code>
+ <para>Tests if a path is rooted.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.has-parent">
+ <indexterm zone="bbv2.reference.modules.path.has-parent">
+ <primary>has-parent</primary>
+ </indexterm>
+ <code language="jam">rule has-parent ( path )</code>
+ <para>Tests if a path has a parent.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.basename">
+ <indexterm zone="bbv2.reference.modules.path.basename">
+ <primary>basename</primary>
+ </indexterm>
+ <code language="jam">rule basename ( path )</code>
+ <para>Returns the path without any directory components.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.parent">
+ <indexterm zone="bbv2.reference.modules.path.parent">
+ <primary>parent</primary>
+ </indexterm>
+ <code language="jam">rule parent ( path )</code>
+ <para>Returns the parent directory of the path. If no parent exists, an error is issued.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.reverse">
+ <indexterm zone="bbv2.reference.modules.path.reverse">
+ <primary>reverse</primary>
+ </indexterm>
+ <code language="jam">rule reverse ( path )</code>
+ <para>
+ Returns <code language="jam">path2</code> such that
+ <code language="jam">[ join path path2 ] = "."</code>.
+ The path may not contain <code language="jam">".."</code>
+ element or be rooted.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.join">
+ <indexterm zone="bbv2.reference.modules.path.join">
+ <primary>join</primary>
+ </indexterm>
+ <code language="jam">rule join ( elements + )</code>
+ <para>
+ Concatenates the passed path elements. Generates an error if any
+ element other than the first one is rooted. Skips any empty or
+ undefined path elements.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.root">
+ <indexterm zone="bbv2.reference.modules.path.root">
+ <primary>root</primary>
+ </indexterm>
+ <code language="jam">rule root ( path root )</code>
+ <para>
+ If <code language="jam">path</code> is relative, it is rooted at
+ <code language="jam">root</code>. Otherwise, it is unchanged.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.pwd">
+ <indexterm zone="bbv2.reference.modules.path.pwd">
+ <primary>pwd</primary>
+ </indexterm>
+ <code language="jam">rule pwd ( )</code>
+ <para>Returns the current working directory.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob">
+ <indexterm zone="bbv2.reference.modules.path.glob">
+ <primary>glob</primary>
+ </indexterm>
+ <code language="jam">rule glob ( dirs * : patterns + : exclude-patterns * )</code>
+ <para>
+ Returns the list of files matching the given pattern in the specified
+ directory. Both directories and patterns are supplied as portable paths. Each
+ pattern should be a non-absolute path, and can't contain "." or ".." elements.
+ Each slash separated element of a pattern can contain the following special
+ characters:
+ <itemizedlist>
+ <listitem>
+ <para>'?' matches any character</para>
+ </listitem>
+ <listitem>
+ <para>'*' matches an arbitrary number of characters</para>
+ </listitem>
+ </itemizedlist>
+ A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches the pattern p1/p2/p3 if and
+ only if e1 matches p1, e2 matches p2 and so on.
+
+ For example:
+<programlisting language="jam">
+[ glob . : *.cpp ]
+[ glob . : */build/Jamfile ]
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob-tree">
+ <indexterm zone="bbv2.reference.modules.path.glob-tree">
+ <primary>glob-tree</primary>
+ </indexterm>
+ <code language="jam">rule glob-tree ( roots * : patterns + : exclude-patterns * )</code>
+ <para>
+ Recursive version of <link linkend="bbv2.reference.modules.path.glob">glob</link>.
+ Builds the glob of files while also searching in
+ the subdirectories of the given roots. An optional set of exclusion patterns
+ will filter out the matching entries from the result. The exclusions also
+ apply to the subdirectory scanning, such that directories that match the
+ exclusion patterns will not be searched.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.exists">
+ <indexterm zone="bbv2.reference.modules.path.exists">
+ <primary>exists</primary>
+ </indexterm>
+ <code language="jam">rule exists ( file )</code>
+ <para>Returns true if the specified file exists.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.all-parents">
+ <indexterm zone="bbv2.reference.modules.path.all-parents">
+ <primary>all-parents</primary>
+ </indexterm>
+ <code language="jam">rule all-parents ( path : upper_limit ? : cwd ? )</code>
+ <para>
+ Find out the absolute name of path and return the list of all the parents,
+ starting with the immediate one. Parents are returned as relative names. If
+ <code language="jam">upper_limit</code> is specified, directories above it
+ will be pruned.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob-in-parents">
+ <indexterm zone="bbv2.reference.modules.path.glob-in-parents">
+ <primary>glob-in-parents</primary>
+ </indexterm>
+ <code language="jam">rule glob-in-parents ( dir : patterns + : upper-limit ? )</code>
+ <para>
+ Search for <code language="jam">patterns</code> in parent directories
+ of <code language="jam">dir</code>, up to and including
+ <code language="jam">upper_limit</code>, if it is specified, or
+ till the filesystem root otherwise.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.relative">
+ <indexterm zone="bbv2.reference.modules.path.relative">
+ <primary>relative</primary>
+ </indexterm>
+ <code language="jam">rule relative ( child parent : no-error ? )</code>
+ <para>
+ Assuming <code language="jam">child</code> is a subdirectory of
+ <code language="jam">parent</code>, return the relative path from
+ <code language="jam">parent</code> to <code language="jam">child</code>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.relative-to">
+ <indexterm zone="bbv2.reference.modules.path.relative-to">
+ <primary>relative-to</primary>
+ </indexterm>
+ <code language="jam">rule relative-to ( path1 path2 )</code>
+ <para>Returns the minimal path to path2 that is relative path1.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.programs-path">
+ <indexterm zone="bbv2.reference.modules.path.programs-path">
+ <primary>programs-path</primary>
+ </indexterm>
+ <code language="jam">rule programs-path ( )</code>
+ <para>
+ Returns the list of paths which are used by the operating system for
+ looking up programs.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.mkdirs">
+ <indexterm zone="bbv2.reference.modules.path.mkdirs">
+ <primary>mkdirs</primary>
+ </indexterm>
+ <code language="jam">rule makedirs ( path )</code>
+ <para>
+ Creates a directory and all parent directories that do not
+ already exist.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/project-target.xml b/tools/build/v2/doc/src/project-target.xml
new file mode 100644
index 0000000000..1e4e39a520
--- /dev/null
+++ b/tools/build/v2/doc/src/project-target.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.project-target">
+
+ <title>Class project-target</title>
+ <indexterm>
+ <primary>project-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class project-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.project-target.generate">generate</link> ( property-set )
+ rule <link linkend="bbv2.reference.class.project-target.build-dir">build-dir</link> ( )
+ rule <link linkend="bbv2.reference.class.project-target.main-target">main-target</link> ( name )
+ rule <link linkend="bbv2.reference.class.project-target.has-main-target">has-main-target</link> ( name )
+ rule <link linkend="bbv2.reference.class.project-target.find">find</link> ( id : no-error ? )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ This class has the following responsibilities:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Maintaining a list of main targets in this project and building them.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.project-target.generate">
+ <indexterm zone="bbv2.reference.class.project-target.generate">
+ <primary>generate</primary>
+ <secondary>Project Target</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Generates virtual targets for all the targets contained in this project.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.build-dir">
+ <indexterm zone="bbv2.reference.class.project-target.build-dir">
+ <primary>build-dir</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule build-dir ( )</code>
+ <para>
+ Returns the root build directory of the project.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.main-target">
+ <indexterm zone="bbv2.reference.class.project-target.main-target">
+ <primary>main-target</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule main-target ( name )</code>
+ <para>
+ Returns a <link linkend="bbv2.reference.class.main-target">main-target</link>
+ class instance corresponding to <literal>name</literal>.
+ Can only be called after the project has been fully loaded.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.has-main-target">
+ <indexterm zone="bbv2.reference.class.project-target.has-main-target">
+ <primary>has-main-target</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule has-main-target ( name )</code>
+ <para>
+ Returns whether a <link linkend="bbv2.reference.class.main-target">main-target</link>
+ with the specified name exists.
+ Can only be called after the project has been fully loaded.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.find">
+ <indexterm zone="bbv2.reference.class.project-target.find">
+ <primary>find</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule find ( id : no-error ? )</code>
+ <para>
+ Find and return the target with the specified id, treated relative to
+ self. Id may specify either a target or a file name with the target taking
+ priority. May report an error or return nothing if the target is not found
+ depending on the <literal>no-error</literal> parameter.
+ </para>
+ </listitem>
+
+ <!--
+
+ I'm not sure whether these should be considered public interfaces.
+ Leave them out for now (SW):
+
+ rule project-module ( )
+ rule get ( attribute )
+
+ -->
+
+ <!--
+
+ The following are not documented because I consider them implementation details (SW):
+
+ rule __init__ ( name : project-module parent-project ?
+ : requirements * : default-build * ) - invoked by the build system.
+
+ rule targets-to-build ( ) - internal to project-target
+ rule mark-target-as-explicit ( target-name * ) - Implementation of explicit
+ rule mark-target-as-always ( target-name * ) - Implementation of always
+ rule add-alternative ( target-instance ) - Implementation of targets.main-target-alternative
+ rule find-really ( id ) - internal to project-target
+ rule build-main-targets ( ) - internal to project-target
+ rule inherit ( parent ) - internal to project-target
+ rule add-constant ( name : value + : type ? ) - Implementation of constant/path-constant
+
+ -->
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/property-set.xml b/tools/build/v2/doc/src/property-set.xml
new file mode 100644
index 0000000000..a5b5b8c7f6
--- /dev/null
+++ b/tools/build/v2/doc/src/property-set.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.property-set">
+
+ <title>Class property-set</title>
+ <indexterm>
+ <primary>property-set</primary>
+ </indexterm>
+
+ <para>Class for storing a set of properties.</para>
+
+<programlisting language="jam">
+class property-set {
+ rule <link linkend="bbv2.reference.class.property-set.raw">raw</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.str">str</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.propagated">propagated</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.add">add</link> ( ps )
+ rule <link linkend="bbv2.reference.class.property-set.add-raw">add-raw</link> ( properties * )
+ rule <link linkend="bbv2.reference.class.property-set.refine">refine</link> ( ps )
+ rule <link linkend="bbv2.reference.class.property-set.get">get</link> ( feature )
+}
+</programlisting>
+
+ <para>
+ There is 1&lt;-&gt;1 correspondence between identity and value. No two instances
+ of the class are equal. To maintain this property, the 'property-set.create'
+ rule should be used to create new instances. Instances are immutable.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.property-set.raw">
+ <indexterm zone="bbv2.reference.class.property-set.raw">
+ <primary>raw</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule raw ( )</code>
+ <para>Returns a Jam list of the stored properties.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.str">
+ <indexterm zone="bbv2.reference.class.property-set.str">
+ <primary>str</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule str ( )</code>
+ <para>Returns the string repesentation of the stored properties.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.propagated">
+ <indexterm zone="bbv2.reference.class.property-set.propagated">
+ <primary>propagated</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule propagated ( )</code>
+ <para>
+ Returns a <link linkend="bbv2.reference.class.property-set">property-set</link>
+ containing all the <link linkend="bbv2.reference.features.attributes.propagated">propagated</link>
+ properties in this <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.add">
+ <indexterm zone="bbv2.reference.class.property-set.add">
+ <primary>add</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule add ( ps )</code>
+ <para>
+ Returns a new <link linkend="bbv2.reference.class.property-set">
+ property-set</link> containing the union of the properties
+ in this <link linkend="bbv2.reference.class.property-set">
+ property-set</link> and in <literal>ps</literal>.
+ <note>
+ <para>
+ If <literal>ps</literal> contains non-free properties
+ that should override the values in this object, use
+ <link linkend="bbv2.reference.class.property-set.refine">
+ refine</link> instead.
+ </para>
+ </note>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.add-raw">
+ <indexterm zone="bbv2.reference.class.property-set.add-raw">
+ <primary>add-raw</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule add-raw ( properties * )</code>
+ <para>
+ Link <link linkend="bbv2.reference.class.property-set.add">
+ add</link>, except that it takes a list of properties
+ instead of a <link linkend="bbv2.reference.class.property-set">
+ property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.refine">
+ <indexterm zone="bbv2.reference.class.property-set.refine">
+ <primary>refine</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule refine ( ps )</code>
+ <para>
+ Refines properties by overriding any non-free and non-conditional
+ properties for which a different value is specified in
+ <literal>ps</literal>. Returns the resulting
+ <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.get">
+ <indexterm zone="bbv2.reference.class.property-set.get">
+ <primary>get</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule get ( feature )</code>
+ <para>
+ Returns all the values of <literal>feature</literal>.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/reference.xml b/tools/build/v2/doc/src/reference.xml
index 80775aaceb..deee17c980 100644
--- a/tools/build/v2/doc/src/reference.xml
+++ b/tools/build/v2/doc/src/reference.xml
@@ -45,7 +45,7 @@ rule boost-build ( location ? )
boost-build build-system ;
</programlisting>
- In this case, running bjam anywhere in the project tree will
+ In this case, running <command>b2</command> anywhere in the project tree will
automatically find the build system.</para>
<para>The default <filename>bootstrap.jam</filename>, after loading some standard
@@ -126,7 +126,7 @@ boost-build build-system ;
<link linkend="bbv2.main-target-rule-syntax">common syntax</link>.</para></listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="bbv2.reference.rules.glob">
<term><literal>glob</literal></term>
<listitem><para>The <code>glob</code> rule takes a list shell pattern
@@ -178,7 +178,7 @@ ECHO [ glob-tree *.cpp : .svn ] ;
</para></listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="bbv2.reference.rules.explicit">
<term><literal>explicit</literal></term>
<listitem><para>The <literal>explicit</literal> rule takes a single
@@ -227,13 +227,13 @@ constant VERSION : 1.34.0 ;
<listitem><para>Same as <literal>constant</literal> except that
the value is treated as path relative to Jamfile location. For example,
- if <command>bjam</command> is invoked in the current directory,
+ if <command>b2</command> is invoked in the current directory,
and Jamfile in <filename>helper</filename> subdirectory has:
<programlisting>
path-constant DATA : data/a.txt ;
</programlisting>
then the variable <varname>DATA</varname> will be set to
- <literal>helper/data/a.txt</literal>, and if <command>bjam</command>
+ <literal>helper/data/a.txt</literal>, and if <command>b2</command>
is invoked from the <filename>helper</filename> directory, then
the variable <varname>DATA</varname> will be set to
<literal>data/a.txt</literal>.
@@ -411,7 +411,7 @@ path-constant DATA : data/a.txt ;
feature, except that it takes effect only for linking. When you want
to link all targets in a Jamfile to certain library, the
<code>&lt;library&gt;</code> feature is preferred over
- <code>&lt;source&gt;X</code> -- the latter will add the library to
+ <code>&lt;source&gt;X</code>&mdash;the latter will add the library to
all targets, even those that have nothing to do with libraries.
</simpara>
</listitem>
@@ -455,6 +455,20 @@ path-constant DATA : data/a.txt ;
</listitem>
</varlistentry>
+ <varlistentry><term><anchor id="bbv2.builtin.features.implicit-dependency"/>
+ <literal>implicit-dependency</literal></term>
+ <indexterm><primary>implicit-dependency</primary></indexterm>
+
+ <listitem>
+ <simpara>
+ Indicates that the target named by the value of this feature
+ may produce files that are included by the sources of the
+ target being declared. See <xref linkend="bbv2.reference.generated_headers"/>
+ for more information.
+ </simpara>
+ </listitem>
+ </varlistentry>
+
<varlistentry><term><anchor id="bbv2.builtin.features.use"/>
<literal>use</literal></term>
@@ -1761,6 +1775,194 @@ using fop : <optional><replaceable>fop-command</replaceable></optional> : <optio
</section>
+ <section id="bbv2.reference.modules">
+ <title>Builtin modules</title>
+
+ <para>
+ This section describes the modules that are provided
+ by Boost.Build. The import rule allows rules from
+ one module to be used in another module or Jamfile.
+ </para>
+
+ <section id="bbv2.reference.modules.modules">
+ <title>modules</title>
+ <indexterm><primary>modules</primary></indexterm>
+
+ <para>
+ The <code>modules</code> module defines basic functionality
+ for handling modules.
+ </para>
+
+ <para>
+ A module defines a number of rules that can be used in other
+ modules. Modules can contain code at the top level to initialize
+ the module. This code is executed the first time the
+ module is loaded.
+ <note>
+ <para>
+ A Jamfile is a special kind of module which is managed by
+ the build system. Although they cannot be loaded directly
+ by users, the other features of modules are still useful
+ for Jamfiles.
+ </para>
+ </note>
+ </para>
+
+ <para>
+ Each module has its own namespaces for variables and rules. If two
+ modules A and B both use a variable named X, each one gets its own
+ copy of X. They won't interfere with each other in any way.
+ Similarly, importing rules into one module has no effect on any other
+ module.
+ </para>
+
+ <para>
+ Every module has two special variables.
+ <code>$(__file__)</code> contains the name of the file that
+ the module was loaded from and <code>$(__name__)</code>
+ contains the name of the module.
+ <note><para><code>$(__file__)</code> does not contain
+ the full path to the file. If you need this, use
+ <code>modules.binding</code>.</para></note>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.modules.binding">
+ <indexterm zone="bbv2.reference.modules.modules.binding"><primary>binding</primary></indexterm>
+ <code language="jam">rule binding ( module-name )</code>
+ <para>Returns the filesystem binding of the given module.</para>
+ <para>For example, a module can get its own location with:
+ <programlisting language="jam">me = [ modules.binding $(__name__) ] ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.poke">
+ <indexterm zone="bbv2.reference.modules.modules.poke"><primary>poke</primary></indexterm>
+ <code language="jam">rule poke ( module-name ? : variables + : value * )</code>
+ <para>Sets the module-local value of a variable.</para>
+ <para>For example, to set a variable in the global module:
+ <programlisting language="jam">modules.poke : ZLIB_INCLUDE : /usr/local/include ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.peek">
+ <indexterm zone="bbv2.reference.modules.modules.peek"><primary>peek</primary></indexterm>
+ <code language="jam">rule peek ( module-name ? : variables + )</code>
+ <para>Returns the module-local value of a variable.</para>
+ <para>
+ For example, to read a variable from the global module:
+ <programlisting language="jam">local ZLIB_INCLUDE = [ modules.peek : ZLIB_INCLUDE ] ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.call-in">
+ <indexterm zone="bbv2.reference.modules.modules.call-in"><primary>call-in</primary></indexterm>
+ <code language="jam">rule call-in ( module-name ? : rule-name args * : * ) </code>
+ <para>Call the given rule locally in the given module. Use
+ this for rules accepting rule names as arguments, so that
+ the passed rule may be invoked in the context of the rule's
+ caller (for example, if the rule accesses module globals or
+ is a local rule).
+ <note><para>rules called this way may accept at most
+ 8 parameters.</para></note></para>
+ <para>Example:
+<programlisting language="jam">
+rule filter ( f : values * )
+{
+ local m = [ CALLER_MODULE ] ;
+ local result ;
+ for v in $(values)
+ {
+ if [ modules.call-in $(m) : $(f) $(v) ]
+ {
+ result += $(v) ;
+ }
+ }
+ return result ;
+}
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.load">
+ <indexterm zone="bbv2.reference.modules.modules.load"><primary>load</primary></indexterm>
+ <code language="jam">rule load ( module-name : filename ? : search * )</code>
+ <para>Load the indicated module if it is not already loaded.</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>module-name</literal></term>
+ <listitem><para>Name of module to load.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><literal>filename</literal></term>
+ <listitem><para>(partial) path to file; Defaults to <code>$(module-name).jam</code></para></listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><literal>search</literal></term>
+ <listitem><para>Directories in which to search for filename.
+ Defaults to <code>$(BOOST_BUILD_PATH)</code>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.import">
+ <indexterm zone="bbv2.reference.modules.modules.import"><primary>import</primary></indexterm>
+ <code language="jam">rule import ( module-names + : rules-opt * : rename-opt * )</code>
+ <para>Load the indicated module and import rule names into the
+ current module. Any members of <code>rules-opt</code> will be
+ available without qualification in the caller's module. Any
+ members of <code>rename-opt</code> will be taken as the names
+ of the rules in the caller's module, in place of the names they
+ have in the imported module. If <code>rules-opt = '*'</code>,
+ all rules from the indicated module are imported into the
+ caller's module. If <code>rename-opt</code> is supplied, it must have the
+ same number of elements as <code>rules-opt</code>.</para>
+ <note><para>The <literal>import</literal> rule is available
+ without qualification in all modules.</para></note>
+ <para>Examples:
+<programlisting language="jam">
+import path ;
+import path : * ;
+import path : join ;
+import path : native make : native-path make-path ;
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.clone-rules">
+ <indexterm zone="bbv2.reference.modules.modules.clone-rules"><primary>clone-rules</primary></indexterm>
+ <code language="jam">rule clone-rules ( source-module target-module )</code>
+ <para>Define exported copies in <code>$(target-module)</code>
+ of all rules exported from <code>$(source-module)</code>. Also
+ make them available in the global module with qualification,
+ so that it is just as though the rules were defined originally
+ in <code>$(target-module)</code>.</para>
+ </listitem>
+
+ </orderedlist>
+
+ </section>
+
+ <xi:include href="path.xml"/>
+ <xi:include href="type.xml"/>
+
+ </section>
+
+ <section id="bbv2.reference.class">
+ <title>Builtin classes</title>
+ <xi:include href="abstract-target.xml"/>
+ <xi:include href="project-target.xml"/>
+ <xi:include href="main-target.xml"/>
+ <xi:include href="basic-target.xml"/>
+ <xi:include href="typed-target.xml"/>
+ <xi:include href="property-set.xml"/>
+ </section>
+
<section id="bbv2.reference.buildprocess">
<title>Build process</title>
@@ -1883,7 +2085,46 @@ exe a : a.cpp
</programlisting>
</para>
- </section>
+ </section>
+
+ <section id="bbv2.reference.buildprocess.targetpath">
+ <title>Target Paths</title>
+
+ <para>Several factors determine the location of a concrete
+ file target. All files in a project are built under
+ the directory bin unless this is overriden by the build-dir project
+ attribute. Under bin is a path that depends on the properties
+ used to build each target. This path is uniquely determined by
+ all non-free, non-incidental properties. For example,
+ given a property set containing:
+ <code>&lt;toolset&gt;gcc &lt;toolset-gcc:version&gt;4.6.1 &lt;variant&gt;debug
+ &lt;warnings&gt;all &lt;define&gt;_DEBUG &lt;include&gt;/usr/local/include
+ &lt;link&gt;static</code>,
+ the path will be gcc-4.6.1/debug/link-static. &lt;warnings&gt; is an
+ incidental feature and &lt;define&gt; and &lt;include&gt; are
+ free features, so they do not affect the path.</para>
+
+ <para>Sometimes the paths produced by Boost.Build can become excessively
+ long. There are a couple of command line options that can help with this.
+ --abbreviate-paths reduces each element to no more than five characters.
+ For example, link-static becomes lnk-sttc. The --hash option reduces the
+ path to a single directory using an MD5 hash.</para>
+
+ <para>There are two features that affect the build
+ directory. The &lt;location&gt; feature completely
+ overrides the default build directory. For example,
+ <programlisting>exe a : a.cpp : &lt;location&gt;. ;</programlisting>
+ builds all the files produced by <code>a</code>
+ in the directory of the Jamfile. This is generally
+ discouraged, as it precludes variant builds.</para>
+
+ <para>The &lt;location-prefix&gt; feature adds a
+ prefix to the path, under the project's build
+ directory. For example,
+ <programlisting>exe a : a.cpp : &lt;location-prefix&gt;subdir ;</programlisting>
+ will create the files for <code>a</code> in bin/subdir/gcc-4.6.1/debug</para>
+
+ </section>
</section>
@@ -1985,7 +2226,7 @@ exe a : a.cpp
<para>Non-incidental features are assumed to affect build
products, so the files for targets whose build specification
differs in non-incidental features are placed in different
- directories as described in "target paths" below. [ where? ]
+ directories as described in <xref linkend="bbv2.reference.buildprocess.targetpath"/>.
</para>
</listitem>
@@ -2041,14 +2282,11 @@ exe a : a.cpp
<listitem>
<para><emphasis>symmetric</emphasis></para>
- <para>A symmetric feature's default value is not automatically
- included in <link linkend=
- "bbv2.reference.variants">build variants</link>. Normally
- a feature only generates a subvariant directory when its
- value differs from the value specified by the build variant,
+ <para>Normally a feature only generates a subvariant directory
+ when its value differs from its default value,
leading to an assymmetric subvariant directory structure for
- certain values of the feature. A symmetric feature, when
- relevant to the toolset, always generates a corresponding
+ certain values of the feature. A symmetric feature
+ always generates a corresponding
subvariant directory.</para>
</listitem>
@@ -2124,24 +2362,6 @@ rule feature ( name : allowed-values * : attributes * )
</section>
</section>
- <section id="bbv2.reference.variants">
- <title>Build Variants</title>
-
- <para>
- A build variant, or (simply variant) is a special kind of composite
- feature that automatically incorporates the default values of
- features that . Typically you'll want at least two separate
- variants: one for debugging, and one for your release code. [
- Volodya says: "Yea, we'd need to mention that it's a composite
- feature and describe how they are declared, in pacticular that
- default values of non-optional features are incorporated into
- build variant automagically. Also, do we wan't some variant
- inheritance/extension/templates. I don't remember how it works in
- V1, so can't document this for V2.". Will clean up soon -DWA ]
- </para>
-
- </section>
-
<section id="bbv2.reference.variants.proprefine">
<title>Property refinement</title>
diff --git a/tools/build/v2/doc/src/standalone.xml b/tools/build/v2/doc/src/standalone.xml
index eea5e101da..22ffff1ee1 100644
--- a/tools/build/v2/doc/src/standalone.xml
+++ b/tools/build/v2/doc/src/standalone.xml
@@ -3,7 +3,7 @@
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude"
- id="bbv2" last-revision="$Date: 2011-01-25 13:06:12 -0500 (Tue, 25 Jan 2011) $">
+ id="bbv2" last-revision="$Date: 2011-01-25 10:06:12 -0800 (Tue, 25 Jan 2011) $">
<bookinfo>
<copyright>
<year>2006</year>
diff --git a/tools/build/v2/doc/src/tasks.xml b/tools/build/v2/doc/src/tasks.xml
index 2b3e68bd16..d6419d4d8f 100644
--- a/tools/build/v2/doc/src/tasks.xml
+++ b/tools/build/v2/doc/src/tasks.xml
@@ -28,7 +28,7 @@ exe hello : hello.cpp some_library.lib /some_project//library
: &lt;threading&gt;multi
;
</programlisting>
- This will create an executable file from the sources -- in this case, one
+ This will create an executable file from the sources&mdash;in this case, one
C++ file, one library file present in the same directory, and another
library that is created by Boost.Build. Generally, sources can include C
and C++ files, object files and libraries. Boost.Build will automatically
@@ -54,6 +54,11 @@ exe hello : hello.cpp some_library.lib /some_project//library
<section id="bbv2.tasks.libraries">
<title>Libraries</title>
+ <indexterm>
+ <primary>library</primary>
+ <secondary>target</secondary>
+ </indexterm>
+
<para>
Library targets are created using the <code>lib</code> rule, which
follows the <link linkend="bbv2.main-target-rule-syntax">common syntax
@@ -63,66 +68,71 @@ lib helpers : helpers.cpp ;
</programlisting>
This will define a library target named <code>helpers</code> built from
the <code>helpers.cpp</code> source file.
+ It can be either a static library or a shared library,
+ depending on the value of the <link linkend="bbv2.overview.builtins.features.link">&lt;link&gt;</link> feature.
</para>
<para>
- Depending on the given &lt;link&gt; feature value the library will be
- either static or shared.
- </para>
- <para>
- Library targets may be used to represent:
+ Library targets can represent:
<itemizedlist>
<listitem>
<para>
- <code>Built libraries</code> that get built from specified sources,
- as is the one in the example above. <!-- add link -->
+ Libraries that should be built from source,
+ as in the example above.
</para>
</listitem>
<listitem>
<para>
- <code>Prebuilt libraries</code> which already exist on the system
- and are just supposed to be used by the build system. Such
- libraries may be searched for by the tools using them (typically
- linkers referencing the library using the <option>-l</option>
- option) or their path may be known in advance by the build system.
- <!-- We need examples for this. -->
+ Prebuilt libraries which already exist on the system.
+ Such libraries can be searched for by the tools using them (typically
+ with the linker's <option>-l</option> option) or their paths can be
+ known in advance by the build system.
</para>
</listitem>
</itemizedlist>
</para>
<para>
- The syntax for these case is given below:
+ The syntax for prebuilt libraries is given below:
<programlisting>
lib z : : &lt;name&gt;z &lt;search&gt;/home/ghost ;
lib compress : : &lt;file&gt;/opt/libs/compress.a ;
</programlisting>
- The <code>name</code> property specifies the name that should be passed to
- the <option>-l</option> option, and the <code>file</code> property
- specifies the file location. The <varname>search</varname> feature
- specifies paths in which to search for the library. That feature can be
- specified several times or it can be omitted, in which case only the
- default compiler paths will be searched.
- </para>
-
- <para>
- The difference between using the <varname>file</varname> feature as
- opposed to the <varname>name</varname> feature together with the <varname>
- search</varname> feature is that <varname>file</varname> is more precise.
- A specific file will be used as opposed to the <varname>search</varname>
- feature only adding a library path, or the <varname>name</varname> feature
- giving only the basic name of the library. The search rules are specific
- to the linker used. For example, given these definition:
+ The <code>name</code> property specifies the name of the library
+ without the standard prefixes and suffixes. For example, depending
+ on the system, <code>z</code> could refer to a file called
+ z.so, libz.a, or z.lib, etc. The <code>search</code> feature
+ specifies paths in which to search for the library in addition
+ to the default compiler paths. <code>search</code> can be specified
+ several times or it can be omitted, in which case only the default
+ compiler paths will be searched. The <code>file</code> property
+ specifies the file location.
+ </para>
+
+ <para>
+ The difference between using the <code>file</code> feature and
+ using a combination of the <code>name</code> and <code>search</code>
+ features is that <code>file</code> is more precise.
+
+ <warning>
+ <para>
+ The value of the <code>search</code> feature is just added to the
+ linker search path. When linking to multiple libraries,
+ the paths specified by <code>search</code> are combined without
+ regard to which <code>lib</code> target each path came from.
+ Thus, given
<programlisting>
-lib a : : &lt;variant&gt;release &lt;file&gt;/pool/release/a.so ;
-lib a : : &lt;variant&gt;debug &lt;file&gt;/pool/debug/a.so ;
-lib b : : &lt;variant&gt;release &lt;file&gt;/pool/release/b.so ;
-lib b : : &lt;variant&gt;debug &lt;file&gt;/pool/debug/b.so ;
+lib a : : &lt;name&gt;a &lt;search&gt;/pool/release ;
+lib b : : &lt;name&gt;b &lt;search&gt;/pool/debug ;
</programlisting>
- It is possible to use a release version of <code>a</code> and debug
- version of <code>b</code>. Had we used the <varname>name</varname> and
- <varname>search</varname> features, the linker would have always picked
- either the release or the debug versions.
- <!-- explain -->
+ If /pool/release/a.so, /pool/release/b.so, /pool/debug/a.so,
+ and /pool/release/b.so all exist, the linker will probably
+ take both <code>a</code> and <code>b</code> from the same
+ directory, instead of finding <code>a</code> in /pool/release
+ and <code>b</code> in /pool/debug. If you need to distinguish
+ between multiple libraries with the same name, it's safer
+ to use <code>file</code>.
+ </para>
+ </warning>
</para>
<para>
@@ -154,18 +164,18 @@ lib png : z : &lt;name&gt;png ;
<note>
<para>
- When a library has a shared library defined as its source, or a static
- library has another static library defined as its source then any target
+ When a library has a shared library as a source, or a static
+ library has another static library as a source then any target
linking to the first library with automatically link to its source
library as well.
</para>
<para>
- On the other hand, when a shared library has a static library defined as
- its source then the first library will be built so that it completely
+ On the other hand, when a shared library has a static library as
+ a source then the first library will be built so that it completely
includes the second one.
</para>
<para>
- If you do not want shared libraries to include all libraries specified
+ If you do not want a shared library to include all the libraries specified
in its sources (especially statically linked ones), you would need to
use the following:
<programlisting>
@@ -173,18 +183,16 @@ lib b : a.cpp ;
lib a : a.cpp : &lt;use&gt;b : : &lt;library&gt;b ;
</programlisting>
This specifies that library <code>a</code> uses library <code>b</code>,
- and causes all executables that link to <code>a</code> also link to
- <code>b</code>. In this case, even for shared linking, the
- <code>a</code> library will not even refer to <code>b</code>.
+ and causes all executables that link to <code>a</code> to link to
+ <code>b</code> also. In this case, even for shared linking, the
+ <code>a</code> library will not refer to <code>b</code>.
</para>
</note>
<para>
- One Boost.Build feature that is often very useful for defining library
- targets are usage requirements. <!-- Rephrase that. But then, it is much
- too late for an introduction of usage requirements - you have already
- discussed them many times. Also, add references to the sections describing
- requirements and usage-requirements here. --> For example, imagine that
+ <!-- FIXME: After adding a full subsection on usage requirements, link to it -->
+ <link linkend="bbv2.overview.targets">Usage requirements</link> are often
+ very useful for defining library targets. For example, imagine that
you want you build a <code>helpers</code> library and its interface is
described in its <code>helpers.hpp</code> header file located in the same
directory as the <code>helpers.cpp</code> source file. Then you could add
@@ -203,7 +211,7 @@ lib helpers : helpers.cpp : : : &lt;include&gt;. ;
<title>Alias</title>
<para>
- The <functionname>alias</functionname> rule gives an alternative name to a
+ The <code language="jam">alias</code> rule gives an alternative name to a
group of targets. For example, to give the name <filename>core</filename>
to a group of three other targets with the following code:
<programlisting>
@@ -384,8 +392,8 @@ unit-test helpers_test : helpers_test.cpp helpers ;
</para>
<para>
- The <functionname>unit-test</functionname> rule behaves like the
- <functionname>exe</functionname> rule, but after the executable is created
+ The <code language="jam">unit-test</code> rule behaves like the
+ <link linkend="bbv2.tasks.programs">exe</link> rule, but after the executable is created
it is also run. If the executable returns an error code, the build system
will also return an error and will try running the executable on the next
invocation until it runs successfully. This behaviour ensures that you can
@@ -476,8 +484,8 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
</para>
<para>
- It is possible to process the list of tests, the output of bjam during
- command run, and the presense/absense of the <filename>*.test</filename>
+ It is possible to process the list of tests, Boost.Build output
+ and the presense/absense of the <filename>*.test</filename>
files created when test passes into human-readable status table of tests.
Such processing utilities are not included in Boost.Build.
</para>
@@ -487,33 +495,33 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
<title>Custom commands</title>
<para>
- When you use most of main target rules, Boost.Build automatically figures
- what commands to run and it what order. As soon as you want to use new
+ For most main target rules, Boost.Build automatically figures out
+ the commands to run. When you want to use new
file types or support new tools, one approach is to extend Boost.Build to
- smoothly support them, as documented in <xref linkend="bbv2.extender"/>.
- However, if there is only a single place where the new tool is used, it
- might be easier to just explicitly specify the commands to run.
+ support them smoothly, as documented in <xref linkend="bbv2.extender"/>.
+ However, if the new tool is only used in a single place, it
+ might be easier just to specify the commands to run explicitly.
</para>
<para>
<!-- This paragraph requires links to where the terms 'virtual target' &
'target' are defined. -->
- Three main target rules can be used for that. The <functionname>make
- </functionname> rule allows you to construct a single file from any number
- of source file, by running a command you specify. The <functionname>
- notfile</functionname> rule allows you to run an arbitrary command,
- without creating any files. And finaly, the <functionname>generate
- </functionname> rule allows you to describe transformation using
- Boost.Build's virtual targets. This is higher-level than file names that
- the <functionname>make</functionname> rule operates with and allows you to
+ Three main target rules can be used for that. The <code language="jam">make
+ </code> rule allows you to construct a single file from any number
+ of source file, by running a command you specify. The <code language="jam">
+ notfile</code> rule allows you to run an arbitrary command,
+ without creating any files. And finaly, the <code language="jam">generate
+ </code> rule allows you to describe a transformation using
+ Boost.Build's virtual targets. This is higher-level than the file names that
+ the <code language="jam">make</code> rule operates with and allows you to
create more than one target, create differently named targets depending on
properties or use more than one tool.
</para>
<para>
- The <functionname>make</functionname> rule is used when you want to create
+ The <code language="jam">make</code> rule is used when you want to create
one file from a number of sources using some specific command. The
- <functionname>notfile</functionname> is used to unconditionally run a
+ <code language="jam">notfile</code> is used to unconditionally run a
command.
</para>
@@ -524,8 +532,8 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
them to become accessible. -->
<para>
- Suppose you want to create file <filename>file.out</filename> from file
- <filename>file.in</filename> by running command <command>
+ Suppose you want to create the file <filename>file.out</filename> from
+ the file <filename>file.in</filename> by running the command <command>
in2out</command>. Here is how you would do this in Boost.Build:
<programlisting>
make file.out : file.in : @in2out ;
@@ -534,7 +542,7 @@ actions in2out
in2out $(&lt;) $(&gt;)
}
</programlisting>
- If you run <command>bjam</command> and <filename>file.out</filename> does
+ If you run <command>b2</command> and <filename>file.out</filename> does
not exist, Boost.Build will run the <command>in2out</command> command to
create that file. For more details on specifying actions, see <xref
linkend="bbv2.overview.jam_language.actions"/>.
@@ -543,7 +551,7 @@ actions in2out
<para>
It could be that you just want to run some command unconditionally, and
that command does not create any specific files. For that you can use the
- <functionname>notfile</functionname> rule. For example:
+ <code language="jam">notfile</code> rule. For example:
<programlisting>
notfile echo_something : @echo ;
actions echo
@@ -551,7 +559,7 @@ actions echo
echo "something"
}
</programlisting>
- The only difference from the <functionname>make</functionname> rule is
+ The only difference from the <code language="jam">make</code> rule is
that the name of the target is not considered a name of a file, so
Boost.Build will unconditionally run the action.
</para>
@@ -559,9 +567,9 @@ actions echo
<para>
<!-- This paragraph requires links to where terms like 'virtual target',
'target', 'project-target' & 'property-set' are defined. -->
- The <functionname>generate</functionname> rule is used when you want to
+ The <code language="jam">generate</code> rule is used when you want to
express transformations using Boost.Build's virtual targets, as opposed to
- just filenames. The <functionname>generate</functionname> rule has the
+ just filenames. The <code language="jam">generate</code> rule has the
standard main target rule signature, but you are required to specify the
<literal>generating-rule</literal> property. The value of the property
should be in the form <literal>
@@ -620,7 +628,7 @@ rule generating-rule ( project name : property-set : sources * )
cpp-pch pch : pch.hpp ;
exe main : main.cpp pch ;
</programlisting>
- You can use the <functionname>c-pch</functionname> rule if you want to
+ You can use the <code language="jam">c-pch</code> rule if you want to
use the precompiled header in C programs.
</para></listitem>
</orderedlist>
@@ -704,7 +712,7 @@ exe main : main.cpp pch ;
Making this mechanism work across main target boundaries is possible, but
imposes certain overhead. For that reason, if there is implicit dependency
on files from other main targets, the <literal>&lt;implicit-dependency&gt;
- </literal> [ link ] feature must be used, for example:
+ </literal> feature must be used, for example:
<programlisting>
lib parser : parser.y ;
exe app : app.cpp : &lt;implicit-dependency&gt;parser ;
@@ -735,7 +743,7 @@ using gcc : arm : arm-none-linux-gnueabi-g++ ;
just request that this compiler version to be used:
</para>
<screen>
-bjam toolset=gcc-arm
+b2 toolset=gcc-arm
</screen>
<para>
@@ -745,9 +753,9 @@ bjam toolset=gcc-arm
</para>
<screen>
# On windows box
-bjam toolset=gcc-arm <emphasis role="bold">target-os=linux</emphasis>
+b2 toolset=gcc-arm <emphasis role="bold">target-os=linux</emphasis>
# On Linux box
-bjam toolset=gcc-mingw <emphasis role="bold">target-os=windows</emphasis>
+b2 toolset=gcc-mingw <emphasis role="bold">target-os=windows</emphasis>
</screen>
<para>
For the complete list of allowed opeating system names, please see the documentation for
diff --git a/tools/build/v2/doc/src/tutorial.xml b/tools/build/v2/doc/src/tutorial.xml
index 3763471dfe..141ed9196f 100644
--- a/tools/build/v2/doc/src/tutorial.xml
+++ b/tools/build/v2/doc/src/tutorial.xml
@@ -30,33 +30,33 @@
<filename>example/hello/</filename> directory. The project is described by
a file called <filename>Jamroot</filename> that contains:
-<programlisting>
+<programlisting language="jam">
exe hello : hello.cpp ;
</programlisting>
Even with this simple setup, you can do some interesting things. First of
- all, just invoking <command>bjam</command> will build the <filename>hello
+ all, just invoking <command>b2</command> will build the <filename>hello
</filename> executable by compiling and linking <filename>hello.cpp
- </filename>. By default, debug variant is built. Now, to build the release
+ </filename>. By default, the debug variant is built. Now, to build the release
variant of <filename>hello</filename>, invoke
<screen>
-bjam release
+b2 release
</screen>
- Note that debug and release variants are created in different directories,
+ Note that the debug and release variants are created in different directories,
so you can switch between variants or even build multiple variants at
once, without any unnecessary recompilation. Let us extend the example by
adding another line to our project's <filename>Jamroot</filename>:
-<programlisting>
+<programlisting language="jam">
exe hello2 : hello.cpp ;
</programlisting>
Now let us build both the debug and release variants of our project again:
<screen>
-bjam debug release
+b2 debug release
</screen>
Note that two variants of <filename>hello2</filename> are linked. Since we
@@ -66,7 +66,7 @@ bjam debug release
let us remove all the built products:
<screen>
-bjam --clean debug release
+b2 --clean debug release
</screen>
It is also possible to build or clean specific targets. The following two
@@ -74,8 +74,8 @@ bjam --clean debug release
<filename>hello2</filename>.
<screen>
-bjam hello2
-bjam --clean hello2
+b2 hello2
+b2 --clean hello2
</screen>
</para>
</section>
@@ -84,9 +84,9 @@ bjam --clean hello2
<title>Properties</title>
<para>
- To portably represent aspects of target configuration such as
+ To represent aspects of target configuration such as
debug and release variants, or single- and multi-threaded
- builds, Boost.Build uses <firstterm>features</firstterm> with
+ builds portably, Boost.Build uses <firstterm>features</firstterm> with
associated <firstterm>values</firstterm>. For
example, the <code>debug-symbols</code> feature can have a value of <code>on</code> or
<code>off</code>. A <firstterm>property</firstterm> is just a (feature,
@@ -102,7 +102,7 @@ bjam --clean hello2
builds the project's <code>release</code> variant with inlining
disabled and debug symbols enabled:
<screen>
-bjam release inlining=off debug-symbols=on
+b2 release inlining=off debug-symbols=on
</screen>
</para>
@@ -116,19 +116,19 @@ bjam release inlining=off debug-symbols=on
<para>
The <option>release</option> and <option>debug</option> that we have seen
- in <command>bjam</command> invocations are just a shorthand way to specify
+ in <command>b2</command> invocations are just a shorthand way to specify
values of the <varname>variant</varname> feature. For example, the
command above could also have been written this way:
<screen>
-bjam variant=release inlining=off debug-symbols=on
+b2 variant=release inlining=off debug-symbols=on
</screen>
</para>
<para>
<varname>variant</varname> is so commonly-used that it has been given
special status as an <firstterm>implicit</firstterm> feature&#x2014;
- Boost.Build will deduce the its identity just from the name of one of its
+ Boost.Build will deduce its identity just from the name of one of its
values.
</para>
@@ -140,7 +140,7 @@ bjam variant=release inlining=off debug-symbols=on
<title>Build Requests and Target Requirements</title>
<para>
- The set of properties specified on the command line constitute
+ The set of properties specified on the command line constitutes
a <firstterm>build request</firstterm>&#x2014;a description of
the desired properties for building the requested targets (or,
if no targets were explicitly requested, the project in the
@@ -160,7 +160,7 @@ bjam variant=release inlining=off debug-symbols=on
illustrates how these requirements might be specified.
</para>
-<programlisting>
+<programlisting language="jam">
exe hello
: hello.cpp
: &lt;include&gt;boost &lt;threading&gt;multi
@@ -170,7 +170,7 @@ exe hello
<para>
When <filename>hello</filename> is built, the two requirements specified
above will always be present. If the build request given on the
- <command>bjam</command> command-line explictly contradicts a target's
+ <command>b2</command> command-line explictly contradicts a target's
requirements, the target requirements usually override (or, in the case
of &#x201C;free&rdquo;&#x201D; features like
<varname>&lt;include&gt;</varname>,
@@ -195,14 +195,15 @@ exe hello
<title>Project Attributes</title>
<para>
- If we want the same requirements for our other target, <filename>hello2
- </filename>, we could simply duplicate them. However, as projects grow,
- that approach leads to a great deal of repeated boilerplate in Jamfiles.
+ If we want the same requirements for our other target,
+ <filename>hello2</filename>, we could simply duplicate them. However,
+ as projects grow, that approach leads to a great deal of repeated
+ boilerplate in Jamfiles.
Fortunately, there's a better way. Each project can specify a set of
<firstterm>attributes</firstterm>, including requirements:
-<programlisting>
+<programlisting language="jam">
project
: requirements &lt;include&gt;/home/ghost/Work/boost &lt;threading&gt;multi
;
@@ -220,8 +221,8 @@ exe hello2 : hello.cpp ;</programlisting>
<title>Project Hierarchies</title>
<para>
- So far we have only considered examples with one project &#x2014;a. with
- one user-written Boost.Jam file, <filename>Jamroot</filename>). A typical
+ So far we have only considered examples with one project, with
+ one user-written Boost.Jam file, <filename>Jamroot</filename>. A typical
large codebase would be composed of many projects organized into a tree.
The top of the tree is called the <firstterm>project root</firstterm>.
Every subproject is defined by a file called <filename>Jamfile</filename>
@@ -271,7 +272,7 @@ top/
any requirements specified by the subproject.
For example, if <filename>top/Jamroot</filename> has
-<programlisting>
+<programlisting language="jam">
&lt;include&gt;/home/ghost/local
</programlisting>
@@ -289,14 +290,14 @@ top/
</para>
<para>
- Invoking <command>bjam</command> without explicitly specifying
+ Invoking <command>b2</command> without explicitly specifying
any targets on the command line builds the project rooted in the
current directory. Building a project does not automatically
cause its subprojects to be built unless the parent project's
Jamfile explicitly requests it. In our example,
<filename>top/Jamroot</filename> might contain:
-<programlisting>
+<programlisting language="jam">
build-project app ;
</programlisting>
@@ -312,7 +313,7 @@ build-project app ;
<title>Dependent Targets</title>
<para>
- When a building a target <filename>X</filename> depends on first
+ When building a target <filename>X</filename> that depends on first
building another target <filename>Y</filename> (such as a
library that must be linked with <firstterm>X</firstterm>),
<filename>Y</filename> is called a
@@ -326,14 +327,14 @@ build-project app ;
use libraries from <filename>top/util/foo</filename>. If
<filename>top/util/foo/Jamfile</filename> contains
-<programlisting>
+<programlisting language="jam">
lib bar : bar.cpp ;
</programlisting>
then to use this library in <filename>top/app/Jamfile</filename>, we can
write:
-<programlisting>
+<programlisting language="jam">
exe app : app.cpp ../util/foo//bar ;
</programlisting>
@@ -352,7 +353,7 @@ exe app : app.cpp ../util/foo//bar ;
<para>Suppose we build <filename>app</filename> with:
<screen>
-bjam app optimization=full define=USE_ASM
+b2 app optimization=full define=USE_ASM
</screen>
Which properties will be used to build <code>foo</code>? The answer is
that some features are
@@ -369,13 +370,13 @@ bjam app optimization=full define=USE_ASM
<para>
Let's improve this project further. The library probably has some headers
that must be used when compiling <filename>app.cpp</filename>. We could
- manually add the necessary <code>#include</code> paths to <filename>app
- </filename>'s requirements as values of the <varname>&lt;include&gt;
- </varname> feature, but then this work will be repeated for all programs
- that use <filename>foo</filename>. A better solution is to modify
- <filename>util/foo/Jamfile</filename> in this way:
+ manually add the necessary <code>#include</code> paths to
+ <filename>app</filename>'s requirements as values of the
+ <varname>&lt;include&gt; </varname> feature, but then this work will be
+ repeated for all programs that use <filename>foo</filename>. A better
+ solution is to modify <filename>util/foo/Jamfile</filename> in this way:
- <programlisting>
+ <programlisting language="jam">
project
: usage-requirements &lt;include&gt;.
;
@@ -397,7 +398,7 @@ lib foo : foo.cpp ;</programlisting>
code to <filename>Jamroot</filename>:
</para>
- <programlisting>
+ <programlisting language="jam">
use-project /library-example/foo : util/foo ;</programlisting>
<para>
@@ -424,7 +425,7 @@ exe app : app.cpp /library-example/foo//bar ;</programlisting>
requirements, like this:
</para>
- <programlisting>
+ <programlisting language="jam">
project
: requirements &lt;library&gt;/boost/filesystem//fs
;</programlisting>
@@ -448,9 +449,9 @@ project
<literal>shared</literal>, and to build a static library, the value should
be <literal>static</literal>. You can request a static build either on the
command line:
- <programlisting>bjam link=static</programlisting>
+ <programlisting>b2 link=static</programlisting>
or in the library's requirements:
- <programlisting>lib l : l.cpp : &lt;link&gt;static ;</programlisting>
+ <programlisting language="jam">lib l : l.cpp : &lt;link&gt;static ;</programlisting>
</para>
<para>
@@ -469,10 +470,10 @@ project
VP: to be addressed when this section is moved. See comment below.
-->
- <programlisting>
+ <programlisting language="jam">
exe important : main.cpp helpers/&lt;link&gt;static ;</programlisting>
- No matter what arguments are specified on the <command>bjam</command>
+ No matter what arguments are specified on the <command>b2</command>
command line, <filename>important</filename> will only be linked with the
static version of <filename>helpers</filename>.
</para>
@@ -484,7 +485,7 @@ exe important : main.cpp helpers/&lt;link&gt;static ;</programlisting>
that library is used by many targets, you <emphasis>could</emphasis> use
target references everywhere:
- <programlisting>
+ <programlisting language="jam">
exe e1 : e1.cpp /other_project//bar/&lt;link&gt;static ;
exe e10 : e10.cpp /other_project//bar/&lt;link&gt;static ;</programlisting>
@@ -497,9 +498,9 @@ alias foo : /other_project//bar/&lt;link&gt;static ;
exe e1 : e1.cpp foo ;
exe e10 : e10.cpp foo ;</programlisting>
- The <link linkend="bbv2.tasks.alias"><functionname>alias</functionname>
- </link> rule is specifically used to rename a reference to a target and
- possibly change the properties.
+ The <link linkend="bbv2.tasks.alias">alias</link> rule is specifically
+ used to rename a reference to a target and possibly change the
+ properties.
<!-- You should introduce the alias rule in an earlier section, before
describing how it applies to this specific use-case, and the
@@ -514,7 +515,7 @@ exe e10 : e10.cpp foo ;</programlisting>
<para>
When one library uses another, you put the second library in the source
list of the first. For example:
- <programlisting>
+ <programlisting language="jam">
lib utils : utils.cpp /boost/filesystem//fs ;
lib core : core.cpp utils ;
exe app : app.cpp core ;</programlisting>
@@ -553,14 +554,14 @@ exe app : app.cpp core ;</programlisting>
<code>release</code> variant is built. This can be achieved using
<firstterm>conditional requirements</firstterm>.
- <programlisting>
+ <programlisting language="jam">
lib network : network.cpp
: <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NEWORK_LIB_SHARED</emphasis>
&lt;variant&gt;release:&lt;define&gt;EXTRA_FAST
;</programlisting>
In the example above, whenever <filename>network</filename> is built with
- <code>&lt;link&gt;shared</code>, <code>&lt;define&gt;NEWORK_LIB_SHARED
+ <code language="jam">&lt;link&gt;shared</code>, <code language="jam">&lt;define&gt;NEWORK_LIB_SHARED
</code> will be in its properties, too. Also, whenever its release variant
is built, <code>&lt;define&gt;EXTRA_FAST</code> will appear in its
properties.
@@ -572,15 +573,15 @@ lib network : network.cpp
library actually uses different source files depending on the toolset used
to build it. We can express this situation using <firstterm>target
alternatives</firstterm>:
- <programlisting>
+ <programlisting language="jam">
lib demangler : dummy_demangler.cpp ; # alternative 1
lib demangler : demangler_gcc.cpp : &lt;toolset&gt;gcc ; # alternative 2
lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3</programlisting>
When building <filename>demangler</filename>, Boost.Build will compare
requirements for each alternative with build properties to find the best
- match. For example, when building with <code>&lt;toolset&gt;gcc</code>
+ match. For example, when building with <code language="jam">&lt;toolset&gt;gcc</code>
alternative 2, will be selected, and when building with
- <code>&lt;toolset&gt;msvc</code> alternative 3 will be selected. In all
+ <code language="jam">&lt;toolset&gt;msvc</code> alternative 3 will be selected. In all
other cases, the most generic alternative 1 will be built.
</para>
</section>
@@ -594,7 +595,7 @@ lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3</prog
<varname>file</varname> property. Target alternatives can be used to
associate multiple library files with a single conceptual target. For
example:
- <programlisting>
+ <programlisting language="jam">
# util/lib2/Jamfile
lib lib2
:
@@ -616,7 +617,7 @@ lib lib2
Once a prebuilt target has been declared, it can be used just like any
other target:
- <programlisting>
+ <programlisting language="jam">
exe app : app.cpp ../util/lib2//lib2 ;</programlisting>
As with any target, the alternative selected depends on the properties
@@ -631,7 +632,7 @@ exe app : app.cpp ../util/lib2//lib2 ;</programlisting>
by searching through some set of predetermined paths&#x2014;should be
declared almost like regular ones:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 ;</programlisting>
We again don't specify any sources, but give a <varname>name</varname>
@@ -644,12 +645,12 @@ lib pythonlib : : &lt;name&gt;python22 ;</programlisting>
<para>
We can also specify where the toolset should look for the library:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 &lt;search&gt;/opt/lib ;</programlisting>
And, of course, target alternatives can be used in the usual way:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 &lt;variant&gt;release ;
lib pythonlib : : &lt;name&gt;python22_d &lt;variant&gt;debug ;</programlisting>
</para>
diff --git a/tools/build/v2/doc/src/type.xml b/tools/build/v2/doc/src/type.xml
new file mode 100644
index 0000000000..6ca7cc7ae1
--- /dev/null
+++ b/tools/build/v2/doc/src/type.xml
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.modules.type">
+
+ <title>type</title>
+ <indexterm>
+ <primary>type</primary>
+ <secondary>module</secondary>
+ </indexterm>
+
+ <para>
+ Deals with target type declaration and defines target class which supports
+ typed targets.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.type.register">
+ <indexterm zone="bbv2.reference.modules.type.register">
+ <primary>register</primary>
+ <secondary>type</secondary>
+ </indexterm>
+ <code language="jam">rule register ( type : suffixes * : base-type ? )</code>
+ <para>
+ Registers a target type, possible derived from a
+ <code language="jam">base-type</code>. Providing a list
+ of suffixes here is a shortcut for separately calling the
+ <link linkend="bbv2.reference.modules.type.register-suffixes">register-suffixes</link>
+ rule with the given suffixes and the
+ <link linkend="bbv2.reference.modules.type.set-generated-target-suffix">set-generated-target-suffix</link>
+ rule with the first given suffix.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.register-suffixes">
+ <indexterm zone="bbv2.reference.modules.type.register-suffixes">
+ <primary>register-suffixes</primary>
+ </indexterm>
+ <code language="jam">rule register-suffixes ( suffixes + : type )</code>
+ <para>
+ Specifies that files with suffix from <code language="jam">suffixes</code>
+ be recognized as targets of type <code language="jam">type</code>.
+ Issues an error if a different type is already specified for any
+ of the suffixes.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.registered">
+ <indexterm zone="bbv2.reference.modules.type.registered">
+ <primary>registered</primary>
+ </indexterm>
+ <code language="jam">rule registered ( type )</code>
+ <para>Returns true iff type has been registered.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.validate">
+ <indexterm zone="bbv2.reference.modules.type.validate">
+ <primary>validate</primary>
+ </indexterm>
+ <code language="jam">rule validate ( type )</code>
+ <para>Issues an error if <code lang="jam">type</code> is unknown.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-scanner">
+ <indexterm zone="bbv2.reference.modules.type.set-scanner">
+ <primary>set-scanner</primary>
+ </indexterm>
+ <code language="jam">rule set-scanner ( type : scanner )</code>
+ <para>Sets a scanner class that will be used for this type.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.get-scanner">
+ <indexterm zone="bbv2.reference.modules.type.get-scanner">
+ <primary>get-scanner</primary>
+ </indexterm>
+ <code language="jam">rule get-scanner ( type : property-set )</code>
+ <para>
+ Returns a scanner instance appropriate to <code language="jam">type</code>
+ and <code language="jam">property-set</code>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.base">
+ <indexterm zone="bbv2.reference.modules.type.base">
+ <primary>base</primary>
+ </indexterm>
+ <code language="jam">rule base ( type )</code>
+ <para>
+ Returns a base type for the given type or nothing in case the given
+ type is not derived.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.all-bases">
+ <indexterm zone="bbv2.reference.modules.type.all-bases">
+ <primary>all-bases</primary>
+ </indexterm>
+ <code language="jam">rule all-bases ( type )</code>
+ <para>
+ Returns the given type and all of its base types in order of
+ their distance from type.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.all-derived">
+ <indexterm zone="bbv2.reference.modules.type.all-derived">
+ <primary>all-derived</primary>
+ </indexterm>
+ <code language="jam">rule all-derived ( type )</code>
+ <para>
+ Returns the given type and all of its derived types in order
+ of their distance from type.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.is-derived">
+ <indexterm zone="bbv2.reference.modules.type.is-derived">
+ <primary>is-derived</primary>
+ </indexterm>
+ <code language="jam">rule is-derived ( type base )</code>
+ <para>
+ Returns true if <code language="jam">type</code> is equal to
+ <code language="jam">base</code> or has <code language="jam">base</code>
+ as its direct or indirect base.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.set-generated-target-suffix">
+ <primary>set-generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule set-generated-target-suffix ( type : properties * : suffix )</code>
+ <para>
+ Sets a file suffix to be used when generating a target of <code language="jam">type</code> with the
+ specified properties. Can be called with no properties if no suffix has
+ already been specified for the <code language="jam">type</code>. The <code language="jam">suffix</code> parameter can be an empty
+ string (<code language="jam">""</code>) to indicate that no suffix should be used.
+ </para>
+
+ <para>
+ Note that this does not cause files with <code language="jam">suffix</code>
+ to be automatically recognized as being of <code language="jam">type</code>.
+ Two different types can use the same suffix for their generated files
+ but only one type can be auto-detected for a file with that suffix.
+ User should explicitly specify which one using the
+ <link linkend="bbv2.reference.modules.type.register-suffixes">register-suffixes</link>
+ rule.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.change-generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.change-generated-target-suffix">
+ <primary>change-generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule change-generated-target-suffix ( type : properties * : suffix )</code>
+ <para>
+ Change the suffix previously registered for this type/properties
+ combination. If suffix is not yet specified, sets it.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.generated-target-suffix">
+ <primary>generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule generated-target-suffix ( type : property-set )</code>
+ <para>
+ Returns the suffix used when generating a file of
+ <code language="jam">type</code> with the given properties.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.set-generated-target-prefix">
+ <primary>set-generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule set-generated-target-prefix ( type : properties * : prefix )</code>
+ <para>
+ Sets a target prefix that should be used when generating targets of
+ <code language="jam">type</code> with the specified properties. Can
+ be called with empty properties if no prefix for
+ <code language="jam">type</code> has been specified yet.
+ </para>
+
+ <para>
+ The <code language="jam">prefix</code> parameter can be empty string
+ (<code language="jam">""</code>) to indicate that no prefix
+ should be used.
+ </para>
+
+ <para>
+ Usage example: library names use the <code language="jam">"lib"</code>
+ prefix on unix.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.change-generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.change-generated-target-prefix">
+ <primary>change-generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule change-generated-target-prefix ( type : properties * : prefix )</code>
+ <para>
+ Change the prefix previously registered for this type/properties
+ combination. If prefix is not yet specified, sets it.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.generated-target-prefix">
+ <primary>generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule generated-target-prefix ( type : property-set )</code>
+ <para>
+ Returns the prefix used when generating a file of
+ <code language="jam">type</code> with the given properties.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.type">
+ <indexterm zone="bbv2.reference.modules.type.type">
+ <primary>type</primary>
+ <secondary>rule</secondary>
+ </indexterm>
+ <code language="jam">rule type ( filename )</code>
+ <para>
+ Returns file type given its name. If there are several
+ dots in filename, tries each suffix. E.g. for name of
+ "file.so.1.2" suffixes "2", "1", and "so" will be tried.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/typed-target.xml b/tools/build/v2/doc/src/typed-target.xml
new file mode 100644
index 0000000000..2a7d7c98c7
--- /dev/null
+++ b/tools/build/v2/doc/src/typed-target.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.typed-target">
+
+ <title>Class typed-target</title>
+ <indexterm>
+ <primary>typed-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class typed-target : <link linkend="bbv2.reference.class.basic-target">basic-target</link> {
+ rule <link linkend="bbv2.reference.class.typed-target.__init__">__init__</link> ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
+ rule <link linkend="bbv2.reference.class.typed-target.type">type</link> ( )
+ rule <link linkend="bbv2.reference.class.typed-target.construct">construct</link> ( name : source-targets * : property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ rule <link linkend="bbv2.reference.class.basic-target.generate">generate</link> ( property-set )
+ }
+</programlisting>
+
+ <para>
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>
+ is the most common kind of target alternative. Rules for creating
+ typed targets are defined automatically for each type.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.typed-target.__init__">
+ <code language="jam">rule __init__ ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem><para>The name of the target</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.class.project-target">project</link>
+ in which the target is declared.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>type</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.modules.type">type</link>
+ of the target.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.typed-target.type">
+ <indexterm zone="bbv2.reference.class.typed-target.type">
+ <primary>type</primary>
+ <secondary>Typed Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule type ( )</code>
+ <para>
+ Returns the <link linkend="bbv2.reference.modules.type">type</link>
+ of the target.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.typed-target.construct">
+ <indexterm zone="bbv2.reference.class.typed-target.construct">
+ <primary>construct</primary>
+ <secondary>Typed Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule construct ( name : source-targets * : property-set )</code>
+ <para>
+ Implements <link linkend="bbv2.reference.class.basic-target.construct">
+ basic-target.construct</link>. Attempts to create a target of
+ the correct type using generators appropriate for the given
+ <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ Returns a <link linkend="bbv2.reference.class.property-set">
+ property-set</link> containing the usage requirements
+ and a list of virtual targets.
+
+ <note>
+ <para>
+ This function is invoked automatically by
+ <link linkend="bbv2.reference.class.basic-target.generate">basic-target.generate</link>
+ and should not be called directly by users.
+ </para>
+ </note>
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/userman.xml b/tools/build/v2/doc/src/userman.xml
index c8f6b685f4..c3f070f39a 100644
--- a/tools/build/v2/doc/src/userman.xml
+++ b/tools/build/v2/doc/src/userman.xml
@@ -3,7 +3,7 @@
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude"
- id="bbv2" last-revision="$Date: 2011-01-25 13:06:12 -0500 (Tue, 25 Jan 2011) $">
+ id="bbv2" last-revision="$Date: 2011-01-25 10:06:12 -0800 (Tue, 25 Jan 2011) $">
<partinfo>
<copyright>
<year>2006</year>
diff --git a/tools/build/v2/engine/build.bat b/tools/build/v2/engine/build.bat
index f927b7697c..2982fb9c93 100644
--- a/tools/build/v2/engine/build.bat
+++ b/tools/build/v2/engine/build.bat
@@ -28,7 +28,7 @@ ECHO ### You can specify the toolset as the argument, i.e.:
ECHO ### .\build.bat msvc
ECHO ###
ECHO ### Toolsets supported by this script are: borland, como, gcc, gcc-nocygwin,
-ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10
+ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11
ECHO ###
call :Set_Error
endlocal
@@ -101,6 +101,16 @@ call :Test_Empty %ProgramFiles%
if not errorlevel 1 set ProgramFiles=C:\Program Files
call :Clear_Error
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ goto :eof)
+call :Clear_Error
+if EXIST "%ProgramFiles%\Microsoft Visual Studio 11.0\VC\VCVARSALL.BAT" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 11.0\VC\"
+ goto :eof)
+call :Clear_Error
if NOT "_%VS100COMNTOOLS%_" == "__" (
set "BOOST_JAM_TOOLSET=vc10"
set "BOOST_JAM_TOOLSET_ROOT=%VS100COMNTOOLS%..\..\VC\"
@@ -371,6 +381,21 @@ set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
set "_known_=1"
:Skip_VC10
+if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc11_" goto Skip_VC11
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ )
+if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS%
+if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
+ if "_%VCINSTALLDIR%_" == "__" (
+ set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%"
+ ) )
+set "BOOST_JAM_CC=cl /nologo /RTC1 /Zi /MTd /Fobootstrap/ /Fdbootstrap/ -DNT -DYYDEBUG -wd4996 kernel32.lib advapi32.lib user32.lib"
+set "BOOST_JAM_OPT_JAM=/Febootstrap\jam0"
+set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
+set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
+set "_known_=1"
+:Skip_VC11
if NOT "_%BOOST_JAM_TOOLSET%_" == "_borland_" goto Skip_BORLAND
if "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
call :Test_Path bcc32.exe )
@@ -438,9 +463,9 @@ echo ###
set YYACC_SOURCES=yyacc.c
set MKJAMBASE_SOURCES=mkjambase.c
set BJAM_SOURCES=
-set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c debug.c execnt.c expand.c filent.c glob.c hash.c
+set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c execnt.c filent.c function.c glob.c hash.c
set BJAM_SOURCES=%BJAM_SOURCES% hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c
-set BJAM_SOURCES=%BJAM_SOURCES% newstr.c option.c output.c parse.c pathunix.c regexp.c
+set BJAM_SOURCES=%BJAM_SOURCES% object.c option.c output.c parse.c pathunix.c regexp.c
set BJAM_SOURCES=%BJAM_SOURCES% rules.c scan.c search.c subst.c timestamp.c variable.c modules.c
set BJAM_SOURCES=%BJAM_SOURCES% strings.c filesys.c builtins.c md5.c pwd.c class.c w32_getreg.c native.c
set BJAM_SOURCES=%BJAM_SOURCES% modules/set.c modules/path.c modules/regex.c
@@ -457,10 +482,13 @@ set test=###%test%###
set test=%test:"###=%
set test=%test:###"=%
set test=%test:###=%
-if "%test%" == "--update" set BJAM_UPDATE=update
+if "%test%" == "--update" goto Found_Update
endlocal
shift
if not "_%BJAM_UPDATE%_" == "_update_" goto Check_Update
+:Found_Update
+endlocal
+set BJAM_UPDATE=update
:Check_Update_End
if "_%BJAM_UPDATE%_" == "_update_" (
if not exist ".\bootstrap\jam0.exe" (
@@ -506,9 +534,6 @@ rename y.tab.h jamgram.h
%BOOST_JAM_CC% %BOOST_JAM_OPT_JAM% %BJAM_SOURCES%
:Skip_Bootstrap
@if not exist ".\bootstrap\jam0.exe" goto Skip_Jam
-@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
-.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " clean
-:Skip_Clean
@set args=%*
@echo OFF
:Set_Args
@@ -526,6 +551,9 @@ set args=%args:~1%
goto Set_Args
:Set_Args_End
@echo ON
+@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
+.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args% clean
+:Skip_Clean
.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args%
:Skip_Jam
diff --git a/tools/build/v2/engine/build.jam b/tools/build/v2/engine/build.jam
index 266b07a17d..1efc3f1f0b 100644
--- a/tools/build/v2/engine/build.jam
+++ b/tools/build/v2/engine/build.jam
@@ -18,12 +18,9 @@ for local v in ARGV CC CFLAGS LIBS
# Platform related specifics.
if $(OS) = NT { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = OS2 { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = VMS { rule .path { return "[.$(<:J=/)]" ; } }
-else if $(OS) = MAC { rule .path { return ":$(<:J=\:)" ; } }
else { rule .path { return "$(<:J=/)" ; } }
-if $(OS) = VMS { . = "_" ; }
-else { . = "." ; }
+
+. = "." ;
./ ?= "" ;
# Info about what we are building.
@@ -71,7 +68,7 @@ if $(with-python)
{
--python-include = [ .path $(python-location) include ] ;
--python-lib = ;
- for local v in 26 25 24 23 22
+ for local v in 27 26 25 24 23 22
{
--python-lib ?=
[ GLOB [ .path $(python-location) libs ] : "python$(v).lib" ]
@@ -94,7 +91,7 @@ if $(with-python)
{
--python-include = ;
--python-lib = ;
- for local v in 2.6 2.5 2.4 2.3 2.2
+ for local v in 2.7 2.6 2.5 2.4 2.3 2.2
{
local inc = [ GLOB [ .path $(python-location) include ] : python$(v) ] ;
local lib = [ GLOB [ .path $(python-location) lib ] : libpython$(v)* ] ;
@@ -214,6 +211,7 @@ toolset gcc gcc : "-o " : -D
: -pedantic -fno-strict-aliasing
[ opt --release : [ opt --symbols : -g : -s ] -O3 ]
[ opt --debug : -g -O0 -fno-inline ]
+ [ opt --profile : -O3 -g -pg ]
-I$(--python-include) -I$(--extra-include) -Wno-long-long
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## GCC 2.x, 3.x on CYGWIN but without cygwin1.dll
@@ -319,14 +317,14 @@ toolset pgi pgcc : "-o " : -D
## Sun Workshop 6 C++
toolset sun cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## Sun Workshop 6 C++ (old alias)
toolset sunpro cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
@@ -372,18 +370,13 @@ toolset vc10 cl : /Fe /Fe /Fd /Fo : -D
[ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
-I$(--python-include) -I$(--extra-include)
: kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
-## VMS/OpenVMS DEC C
-toolset vmsdecc cc : /OBJECT= : "/DEFINES=(" "," ")"
- : /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
- [ opt --release : /OPTIMIZE /NODEBUG ]
- [ opt --debug : /NOOPTIMIZE /DEBUG ]
- ;
-toolset vmsdecc link .link : /EXECUTABLE= :
- : /NOMAP
- [ opt --release : /NODEBUG ]
- [ opt --debug : /DEBUG ]
- ;
-
+toolset vc11 cl : /Fe /Fe /Fd /Fo : -D
+ : /nologo
+ [ opt --release : /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ]
+ [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
+ -I$(--python-include) -I$(--extra-include)
+ : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
+
# First set the build commands and options according to the
# preset toolset.
toolset = [ MATCH --toolset=(.*) : $(ARGV) ] ;
@@ -454,17 +447,7 @@ if $(tool.$(toolset).link.cc)
# Put executables in platform-specific subdirectory.
locate-target = $(LOCATE_TARGET) ;
-if $(OS) = VMS
-{
- locate-target ?= bin$(.)vms ;
- platform = vms ;
-}
-else if $(OS) = MAC
-{
- locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
- platform = $(OS:L)$(OSPLAT:L) ;
-}
-else if $(OSPLAT)
+if $(OSPLAT)
{
locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
platform = $(OS:L)$(OSPLAT:L) ;
@@ -492,12 +475,12 @@ if --show-locate-target in $(ARGV)
ECHO $(locate-target) ;
}
-# We have some different files for UNIX, VMS, and NT.
+# We have some different files for UNIX, and NT.
jam.source =
- command.c compile.c debug.c expand.c glob.c
+ command.c compile.c constants.c debug.c function.c glob.c
hash.c hcache.c headers.c hdrmacro.c
jam.c jambase.c jamgram.c
- lists.c make.c make1.c mem.c newstr.c
+ lists.c make.c make1.c mem.c object.c
option.c output.c parse.c regexp.c rules.c
scan.c search.c subst.c w32_getreg.c
timestamp.c variable.c modules.c strings.c filesys.c
@@ -509,18 +492,6 @@ if $(OS) = NT
{
jam.source += execnt.c filent.c pathunix.c ;
}
-else if $(OS) = OS2
-{
- jam.source += execunix.c fileos2.c pathunix.c ;
-}
-else if $(OS) = VMS
-{
- jam.source += execvms.c filevms.c pathvms.c ;
-}
-else if $(OS) = MAC
-{
- jam.source += execmac.c filemac.c pathmac.c ;
-}
else
{
jam.source += execunix.c fileunix.c pathunix.c ;
@@ -565,10 +536,6 @@ if ( $(OS) = NT ) && ! NT in $(--defs)
{
--defs += NT ;
}
-if $(OS) = VMS
-{
- --defs += VMS ;
-}
--defs += YYSTACKSIZE=5000 ;
if $(with-python)
@@ -597,18 +564,12 @@ if $(OS) = NT { actions piecemeal together existing [DELETE] {
if $(UNIX) = true { actions piecemeal together existing [DELETE] {
rm -f "$(>)"
} }
-if $(OS) = VMS { actions piecemeal together existing [DELETE] {
- DELETE $(>[--2]:J=";*, ") $(>[-1]);*
-} }
if $(OS) = NT {
--chmod+w = "attrib -r " ;
}
if $(UNIX) = true {
--chmod+w = "chmod +w " ;
}
-if $(OS) = VMS {
- --chmod+w = "SET FILE/PROT=(S:RWED) " ;
-}
rule .mkdir
{
@@ -622,14 +583,11 @@ if $(OS) = NT { actions [MKDIR] {
if $(UNIX) = true { actions [MKDIR] {
mkdir "$(<)"
} }
-if $(OS) = VMS { actions [MKDIR] {
- CREATE/DIR $(<J=", ")
-} }
rule .exe
{
local exe = $(<) ;
- if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) || $(OS) = VMS { exe = $(exe:S=.exe) ; }
+ if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) { exe = $(exe:S=.exe) ; }
LOCATE on $(exe) = $(locate-target) ;
DEPENDS all : $(exe) ;
.mkdir $(locate-target) ;
@@ -665,18 +623,16 @@ rule .exe
return $(exe) ;
}
if ! $(--def[2]) { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(--libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(>)" "$(--libs)"
} }
else { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(--libs)" "$(>)"
-} }
-if $(OS) = VMS { actions [COMPILE.LINK] {
- "$(--link)" $(--link-bin)$(<:D=) $(--link-dir)$(<:D)$(./) $(--link-out)$(<) $(--link-def)$(--link-defs) $(--link-flags) "$(--link-libs)" $(>J=", ")
-} }
-else { actions [COMPILE.LINK] {
- "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(--link-libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(>)" "$(--libs)"
} }
+actions [COMPILE.LINK] {
+ "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(>)" "$(--link-libs)"
+}
+
rule .link
{
DEPENDS all : $(<) ;
@@ -690,9 +646,6 @@ if $(OS) = NT { actions [LINK] {
if $(UNIX) = true { actions [LINK] {
ln -fs "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [LINK] {
- COPY/REPLACE $(>) $(<)
-} }
rule .copy
{
@@ -720,9 +673,6 @@ if $(OS) = NT { actions [MOVE] {
if $(UNIX) = true { actions [MOVE] {
mv -f "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [MOVE] {
- RENAME "$(>)" "$(<)"
-} }
# Generate the grammar tokens table, and the real yacc grammar.
rule .yyacc
@@ -796,13 +746,6 @@ if $(UNIX) = true { actions [YACC] {
exit 1
fi
} }
-if $(OS) = VMS { actions [YACC] {
- IF "$(yacc)" $(>)
- THEN
- RENAME y_tab$(<[1]:S) $(<[1])
- RENAME y_tab$(<[2]:S) $(<[2])
- ENDIF
-} }
if $(grammar) && ! $(yacc)
{
EXIT "Could not find the 'yacc' tool, and therefore can not build the grammar." ;
@@ -888,7 +831,7 @@ dist.source =
dist.source = $(dist.source:D=)
$(dist.license[1])
$(dist.docs)
- build.jam build.bat build.sh build_vms.com
+ build.jam build.bat build.sh
Jambase
jamgram.y jamgram.yy
[ .path modules set.c ]
diff --git a/tools/build/v2/engine/build.sh b/tools/build/v2/engine/build.sh
index f1fb806d3c..e3a4498b7a 100755
--- a/tools/build/v2/engine/build.sh
+++ b/tools/build/v2/engine/build.sh
@@ -245,9 +245,9 @@ echo "###"
YYACC_SOURCES="yyacc.c"
MKJAMBASE_SOURCES="mkjambase.c"
BJAM_SOURCES="\
- command.c compile.c debug.c expand.c glob.c hash.c\
+ command.c compile.c constants.c debug.c function.c glob.c hash.c\
hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\
- newstr.c option.c output.c parse.c pathunix.c pathvms.c regexp.c\
+ object.c option.c output.c parse.c pathunix.c regexp.c\
rules.c scan.c search.c subst.c timestamp.c variable.c modules.c\
strings.c filesys.c builtins.c pwd.c class.c native.c md5.c w32_getreg.c\
modules/set.c modules/path.c modules/regex.c modules/property-set.c\
@@ -297,7 +297,7 @@ if test "${BJAM_UPDATE}" != "update" ; then
fi
if test -x "./bootstrap/jam0" ; then
if test "${BJAM_UPDATE}" != "update" ; then
- echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" clean
+ echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@" clean
fi
echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@"
fi
diff --git a/tools/build/v2/engine/build_vms.com b/tools/build/v2/engine/build_vms.com
deleted file mode 100644
index 965b634247..0000000000
--- a/tools/build/v2/engine/build_vms.com
+++ /dev/null
@@ -1,105 +0,0 @@
-$ ! Copyright 2002-2003 Rene Rivera, Johan Nilsson.
-$ ! Distributed under the Boost Software License, Version 1.0.
-$ ! (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-$ !
-$ ! bootstrap build script for Jam
-$ !
-$ SAY :== WRITE SYS$OUTPUT
-$ !
-$ ON WARNING THEN CONTINUE
-$ !
-$ IF "" .NES. F$SEARCH("[.bootstrap_vms]*.*")
-$ THEN
-$ SAY "Cleaning previous boostrap files..."
-$ !
-$ SET FILE/PROTECTION=(S:RWED) [.bootstrap_vms]*.*;*
-$ DELETE [.bootstrap_vms]*.*;*
-$ ENDIF
-$ !
-$ IF "" .NES. F$SEARCH("bootstrap_vms.dir")
-$ THEN
-$ SAY "Removing previous boostrap directory..."
-$ !
-$ SET FILE/PROT=(S:RWED) bootstrap_vms.dir
-$ DELETE bootstrap_vms.dir;
-$ ENDIF
-$ !
-$ SAY "Creating boostrap directory..."
-$ !
-$ CREATE/DIR [.bootstrap_vms]
-$ !
-$ SAY "Building bootstrap jam..."
-$ !
-$ CC_FLAGS = "/DEFINE=VMS /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES "
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]builtins.obj builtins.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]command.obj command.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]compile.obj compile.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]execvms.obj execvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]expand.obj expand.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filesys.obj filesys.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filevms.obj filevms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]glob.obj glob.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hash.obj hash.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hdrmacro.obj hdrmacro.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]headers.obj headers.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jam.obj jam.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jambase.obj jambase.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jamgram.obj jamgram.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]lists.obj lists.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make.obj make.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make1.obj make1.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]modules.obj modules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]newstr.obj newstr.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]option.obj option.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]parse.obj parse.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pathvms.obj pathvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pwd.obj pwd.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]regexp.obj regexp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]rules.obj rules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]scan.obj scan.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]search.obj search.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]strings.obj strings.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]subst.obj subst.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]timestamp.obj timestamp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]variable.obj variable.c
-$ link -
- /EXECUTABLE=[.bootstrap_vms]jam0.exe -
- [.bootstrap_vms]builtins.obj, -
- [.bootstrap_vms]command.obj, -
- [.bootstrap_vms]compile.obj, -
- [.bootstrap_vms]execvms.obj, -
- [.bootstrap_vms]expand.obj, -
- [.bootstrap_vms]filesys.obj, -
- [.bootstrap_vms]filevms.obj, -
- [.bootstrap_vms]glob.obj, -
- [.bootstrap_vms]hash.obj, -
- [.bootstrap_vms]hdrmacro.obj, -
- [.bootstrap_vms]headers.obj, -
- [.bootstrap_vms]jam.obj, -
- [.bootstrap_vms]jambase.obj, -
- [.bootstrap_vms]jamgram.obj, -
- [.bootstrap_vms]lists.obj, -
- [.bootstrap_vms]make.obj, -
- [.bootstrap_vms]make1.obj, -
- [.bootstrap_vms]modules.obj, -
- [.bootstrap_vms]newstr.obj, -
- [.bootstrap_vms]option.obj, -
- [.bootstrap_vms]parse.obj, -
- [.bootstrap_vms]pathvms.obj, -
- [.bootstrap_vms]pwd.obj, -
- [.bootstrap_vms]regexp.obj, -
- [.bootstrap_vms]rules.obj, -
- [.bootstrap_vms]scan.obj, -
- [.bootstrap_vms]search.obj, -
- [.bootstrap_vms]strings.obj, -
- [.bootstrap_vms]subst.obj, -
- [.bootstrap_vms]timestamp.obj, -
- [.bootstrap_vms]variable.obj
-$ !
-$ SAY "Cleaning any previous build..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc clean
-$ !
-$ SAY "Building Boost.Jam..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc
diff --git a/tools/build/v2/engine/builtins.c b/tools/build/v2/engine/builtins.c
index b28a484ec4..07eaa1534a 100644
--- a/tools/build/v2/engine/builtins.c
+++ b/tools/build/v2/engine/builtins.c
@@ -11,7 +11,7 @@
#include "builtins.h"
#include "rules.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "regexp.h"
#include "frames.h"
#include "hash.h"
@@ -25,6 +25,7 @@
#include "variable.h"
#include "timestamp.h"
#include "md5.h"
+#include "constants.h"
#include <ctype.h>
#if defined(USE_EXECUNIX)
@@ -65,38 +66,44 @@
*/
#define P0 (PARSE *)0
-#define C0 (char *)0
+#define C0 (OBJECT *)0
#if defined( OS_NT ) || defined( OS_CYGWIN )
- LIST * builtin_system_registry ( PARSE *, FRAME * );
- LIST * builtin_system_registry_names( PARSE *, FRAME * );
+ LIST * builtin_system_registry ( FRAME *, int );
+ LIST * builtin_system_registry_names( FRAME *, int );
#endif
-int glob( char * s, char * c );
+int glob( const char * s, const char * c );
void backtrace ( FRAME * );
void backtrace_line ( FRAME * );
-void print_source_line( PARSE * );
+void print_source_line( FRAME * );
-RULE * bind_builtin( char * name, LIST * (* f)( PARSE *, FRAME * ), int flags, char * * args )
+RULE * bind_builtin( const char * name_, LIST * (* f)( FRAME *, int flags ), int flags, const char * * args )
{
- argument_list* arg_list = 0;
+ FUNCTION * func;
+ RULE * result;
+ OBJECT * name = object_new( name_ );
- if ( args )
- {
- arg_list = args_new();
- lol_build( arg_list->data, args );
- }
+ func = function_builtin( f, flags, args );
+
+ result = new_rule_body( root_module(), name, func, 1 );
+
+ function_free( func );
+
+ object_free( name );
- return new_rule_body( root_module(), name, arg_list,
- parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
+ return result;
}
-RULE * duplicate_rule( char * name, RULE * other )
+RULE * duplicate_rule( const char * name_, RULE * other )
{
- return import_rule( other, root_module(), name );
+ OBJECT * name = object_new( name_ );
+ RULE * result = import_rule( other, root_module(), name );
+ object_free( name );
+ return result;
}
@@ -116,7 +123,7 @@ void load_builtins()
builtin_echo, 0, 0 ) ) );
{
- char * args[] = { "message", "*", ":", "result-value", "?", 0 };
+ const char * args[] = { "message", "*", ":", "result-value", "?", 0 };
duplicate_rule( "exit",
duplicate_rule( "Exit",
bind_builtin( "EXIT",
@@ -124,13 +131,13 @@ void load_builtins()
}
{
- char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
+ const char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
duplicate_rule( "Glob",
bind_builtin( "GLOB", builtin_glob, 0, args ) );
}
{
- char * args[] = { "patterns", "*", 0 };
+ const char * args[] = { "patterns", "*", 0 };
bind_builtin( "GLOB-RECURSIVELY",
builtin_glob_recursive, 0, args );
}
@@ -140,7 +147,7 @@ void load_builtins()
builtin_depends, 1, 0 ) );
{
- char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
+ const char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
bind_builtin( "REBUILDS",
builtin_rebuilds, 0, args );
}
@@ -154,7 +161,7 @@ void load_builtins()
builtin_match, 0, 0 ) );
{
- char * args[] = { "string", ":", "delimiters" };
+ const char * args[] = { "string", ":", "delimiters" };
bind_builtin( "SPLIT_BY_CHARACTERS",
builtin_split_by_characters, 0, 0 );
}
@@ -194,13 +201,13 @@ void load_builtins()
builtin_flags, T_FLAG_RMOLD, 0 );
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "UPDATE",
builtin_update, 0, args );
}
{
- char * args[] = { "targets", "*",
+ const char * args[] = { "targets", "*",
":", "log", "?",
":", "ignore-minus-n", "?",
":", "ignore-minus-q", "?", 0 };
@@ -209,33 +216,33 @@ void load_builtins()
}
{
- char * args[] = { "string", "pattern", "replacements", "+", 0 };
+ const char * args[] = { "string", "pattern", "replacements", "+", 0 };
duplicate_rule( "subst",
bind_builtin( "SUBST",
builtin_subst, 0, args ) );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "RULENAMES",
builtin_rulenames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "VARNAMES",
builtin_varnames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "DELETE_MODULE",
builtin_delete_module, 0, args );
}
{
- char * args[] = { "source_module", "?",
+ const char * args[] = { "source_module", "?",
":", "source_rules", "*",
":", "target_module", "?",
":", "target_rules", "*",
@@ -245,104 +252,98 @@ void load_builtins()
}
{
- char * args[] = { "module", "?", ":", "rules", "*", 0 };
+ const char * args[] = { "module", "?", ":", "rules", "*", 0 };
bind_builtin( "EXPORT",
builtin_export, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "CALLER_MODULE",
builtin_caller_module, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "BACKTRACE",
builtin_backtrace, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "PWD",
builtin_pwd, 0, args );
}
{
- char * args[] = { "target", "*", ":", "path", "*", 0 };
- bind_builtin( "SEARCH_FOR_TARGET",
- builtin_search_for_target, 0, args );
- }
-
- {
- char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
+ const char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
bind_builtin( "IMPORT_MODULE",
builtin_import_module, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "IMPORTED_MODULES",
builtin_imported_modules, 0, args );
}
{
- char * args[] = { "instance_module", ":", "class_module", 0 };
+ const char * args[] = { "instance_module", ":", "class_module", 0 };
bind_builtin( "INSTANCE",
builtin_instance, 0, args );
}
{
- char * args[] = { "sequence", "*", 0 };
+ const char * args[] = { "sequence", "*", 0 };
bind_builtin( "SORT",
builtin_sort, 0, args );
}
{
- char * args[] = { "path_parts", "*", 0 };
+ const char * args[] = { "path_parts", "*", 0 };
bind_builtin( "NORMALIZE_PATH",
builtin_normalize_path, 0, args );
}
{
- char * args[] = { "args", "*", 0 };
+ const char * args[] = { "args", "*", 0 };
bind_builtin( "CALC",
builtin_calc, 0, args );
}
{
- char * args[] = { "module", ":", "rule", 0 };
+ const char * args[] = { "module", ":", "rule", 0 };
bind_builtin( "NATIVE_RULE",
builtin_native_rule, 0, args );
}
{
- char * args[] = { "module", ":", "rule", ":", "version", 0 };
+ const char * args[] = { "module", ":", "rule", ":", "version", 0 };
bind_builtin( "HAS_NATIVE_RULE",
builtin_has_native_rule, 0, args );
}
{
- char * args[] = { "module", "*", 0 };
+ const char * args[] = { "module", "*", 0 };
bind_builtin( "USER_MODULE",
builtin_user_module, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "NEAREST_USER_LOCATION",
builtin_nearest_user_location, 0, args );
}
{
- char * args[] = { "file", 0 };
+ const char * args[] = { "file", 0 };
bind_builtin( "CHECK_IF_FILE",
builtin_check_if_file, 0, args );
}
#ifdef HAVE_PYTHON
{
- char * args[] = { "python-module", ":", "function", ":",
+ const char * args[] = { "python-module", ":", "function", ":",
"jam-module", ":", "rule-name", 0 };
bind_builtin( "PYTHON_IMPORT_RULE",
builtin_python_import_rule, 0, args );
@@ -351,56 +352,56 @@ void load_builtins()
# if defined( OS_NT ) || defined( OS_CYGWIN )
{
- char * args[] = { "key_path", ":", "data", "?", 0 };
+ const char * args[] = { "key_path", ":", "data", "?", 0 };
bind_builtin( "W32_GETREG",
builtin_system_registry, 0, args );
}
{
- char * args[] = { "key_path", ":", "result-type", 0 };
+ const char * args[] = { "key_path", ":", "result-type", 0 };
bind_builtin( "W32_GETREGNAMES",
builtin_system_registry_names, 0, args );
}
# endif
{
- char * args[] = { "command", ":", "*", 0 };
+ const char * args[] = { "command", ":", "*", 0 };
duplicate_rule( "SHELL",
bind_builtin( "COMMAND",
builtin_shell, 0, args ) );
}
{
- char * args[] = { "string", 0 };
+ const char * args[] = { "string", 0 };
bind_builtin( "MD5",
builtin_md5, 0, args ) ;
}
{
- char * args[] = { "name", ":", "mode", 0 };
+ const char * args[] = { "name", ":", "mode", 0 };
bind_builtin( "FILE_OPEN",
builtin_file_open, 0, args );
}
{
- char * args[] = { "string", ":", "width", 0 };
+ const char * args[] = { "string", ":", "width", 0 };
bind_builtin( "PAD",
builtin_pad, 0, args );
}
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "PRECIOUS",
builtin_precious, 0, args );
}
{
- char * args [] = { 0 };
+ const char * args [] = { 0 };
bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
}
{
- char * args [] = { "path", 0 };
+ const char * args [] = { "path", 0 };
bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
}
@@ -420,11 +421,11 @@ void load_builtins()
* The CALC rule performs simple mathematical operations on two arguments.
*/
-LIST * builtin_calc( PARSE * parse, FRAME * frame )
+LIST * builtin_calc( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
long lhs_value;
long rhs_value;
long result_value;
@@ -432,17 +433,18 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
char const * lhs;
char const * op;
char const * rhs;
+ LISTITER iter = list_begin( arg ), end = list_end( arg );
- if ( arg == 0 ) return L0;
- lhs = arg->string;
+ if ( iter == end ) return L0;
+ lhs = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- op = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ op = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- rhs = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ rhs = object_str( list_item( iter ) );
lhs_value = atoi( lhs );
rhs_value = atoi( rhs );
@@ -461,7 +463,7 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
}
sprintf( buffer, "%ld", result_value );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
return result;
}
@@ -474,21 +476,22 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
* targets and sources as TARGETs.
*/
-LIST * builtin_depends( PARSE * parse, FRAME * frame )
+LIST * builtin_depends( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * sources = lol_get( frame->args, 1 );
- LIST * l;
-
- for ( l = targets; l; l = list_next( l ) )
+ LISTITER iter, end;
+
+ iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* If doing INCLUDES, switch to the TARGET's include */
/* TARGET, creating it if needed. The internal include */
/* TARGET shares the name of its parent. */
- if ( parse->num )
+ if ( flags )
{
if ( !t->includes )
{
@@ -502,9 +505,10 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
}
/* Enter reverse links */
- for ( l = sources; l; l = list_next( l ) )
+ iter = list_begin( sources ), end = list_end( sources );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * s = bindtarget( l->string );
+ TARGET * s = bindtarget( list_item( iter ) );
s->dependants = targetlist( s->dependants, targets );
}
@@ -520,15 +524,15 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
* argument.
*/
-LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
+LIST * builtin_rebuilds( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * rebuilds = lol_get( frame->args, 1 );
- LIST * l;
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
- for ( l = targets; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
t->rebuilds = targetlist( t->rebuilds, rebuilds );
}
@@ -543,7 +547,7 @@ LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
* taken.
*/
-LIST * builtin_echo( PARSE * parse, FRAME * frame )
+LIST * builtin_echo( FRAME * frame, int flags )
{
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
@@ -559,13 +563,14 @@ LIST * builtin_echo( PARSE * parse, FRAME * frame )
* with a failure status.
*/
-LIST * builtin_exit( PARSE * parse, FRAME * frame )
+LIST * builtin_exit( FRAME * frame, int flags )
{
+ LIST * code = lol_get( frame->args, 1 );
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
- if ( lol_get( frame->args, 1 ) )
+ if ( !list_empty( code ) )
{
- exit( atoi( lol_get( frame->args, 1 )->string ) );
+ exit( atoi( object_str( list_front( code ) ) ) );
}
else
{
@@ -582,11 +587,12 @@ LIST * builtin_exit( PARSE * parse, FRAME * frame )
* It binds each target as a TARGET.
*/
-LIST * builtin_flags( PARSE * parse, FRAME * frame )
+LIST * builtin_flags( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = list_next( l ) )
- bindtarget( l->string )->flags |= parse->num;
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ bindtarget( list_item( iter ) )->flags |= flags;
return L0;
}
@@ -612,10 +618,10 @@ static void downcase_inplace( char * p )
static void builtin_glob_back
(
- void * closure,
- char * file,
- int status,
- time_t time
+ void * closure,
+ OBJECT * file,
+ int status,
+ time_t time
)
{
PROFILE_ENTER( BUILTIN_GLOB_BACK );
@@ -624,15 +630,16 @@ static void builtin_glob_back
LIST * l;
PATHNAME f;
string buf[ 1 ];
+ LISTITER iter, end;
/* Null out directory for matching. We wish we had file_dirscan() pass up a
* PATHNAME.
*/
- path_parse( file, &f );
+ path_parse( object_str( file ), &f );
f.f_dir.len = 0;
/* For globbing, we unconditionally ignore current and parent directory
- * items. Since they items always exist, there is no reason why caller of
+ * items. Since these items always exist, there is no reason why caller of
* GLOB would want to see them. We could also change file_dirscan(), but
* then paths with embedded "." and ".." would not work anywhere.
*/
@@ -648,11 +655,12 @@ static void builtin_glob_back
if ( globbing->case_insensitive )
downcase_inplace( buf->value );
- for ( l = globbing->patterns; l; l = l->next )
+ iter = list_begin( globbing->patterns ), end = list_end( globbing->patterns );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !glob( l->string, buf->value ) )
+ if ( !glob( object_str( list_item( iter ) ), buf->value ) )
{
- globbing->results = list_new( globbing->results, newstr( file ) );
+ globbing->results = list_push_back( globbing->results, object_copy( file ) );
break;
}
}
@@ -665,17 +673,18 @@ static void builtin_glob_back
static LIST * downcase_list( LIST * in )
{
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER iter = list_begin( in ), end = list_end( in );
string s[ 1 ];
string_new( s );
- while ( in )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- string_copy( s, in->string );
+ string_append( s, object_str( list_item( iter ) ) );
downcase_inplace( s->value );
- result = list_append( result, list_new( 0, newstr( s->value ) ) );
- in = in->next;
+ result = list_push_back( result, object_new( s->value ) );
+ string_truncate( s, 0 );
}
string_free( s );
@@ -683,11 +692,12 @@ static LIST * downcase_list( LIST * in )
}
-LIST * builtin_glob( PARSE * parse, FRAME * frame )
+LIST * builtin_glob( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
LIST * r = lol_get( frame->args, 1 );
+ LISTITER iter, end;
struct globbing globbing;
globbing.results = L0;
@@ -703,8 +713,9 @@ LIST * builtin_glob( PARSE * parse, FRAME * frame )
if ( globbing.case_insensitive )
globbing.patterns = downcase_list( r );
- for ( ; l; l = list_next( l ) )
- file_dirscan( l->string, builtin_glob_back, &globbing );
+ iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ file_dirscan( list_item( iter ), builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
list_free( globbing.patterns );
@@ -724,19 +735,19 @@ static int has_wildcards( char const * str )
* If 'file' exists, append 'file' to 'list'. Returns 'list'.
*/
-static LIST * append_if_exists( LIST * list, char * file )
+static LIST * append_if_exists( LIST * list, OBJECT * file )
{
time_t time;
timestamp( file, &time );
return time > 0
- ? list_new( list, newstr( file ) )
+ ? list_push_back( list, object_copy( file ) )
: list;
}
-LIST * glob1( char * dirname, char * pattern )
+LIST * glob1( OBJECT * dirname, OBJECT * pattern )
{
- LIST * plist = list_new( L0, pattern );
+ LIST * plist = list_new( object_copy(pattern) );
struct globbing globbing;
globbing.results = L0;
@@ -763,7 +774,7 @@ LIST * glob1( char * dirname, char * pattern )
}
-LIST * glob_recursive( char * pattern )
+LIST * glob_recursive( const char * pattern )
{
LIST * result = L0;
@@ -771,7 +782,9 @@ LIST * glob_recursive( char * pattern )
if ( !has_wildcards( pattern ) )
{
/* No metacharacters. Check if the path exists. */
- result = append_if_exists(result, pattern);
+ OBJECT * p = object_new( pattern );
+ result = append_if_exists( result, p );
+ object_free( p );
}
else
{
@@ -798,27 +811,35 @@ LIST * glob_recursive( char * pattern )
dirs = has_wildcards( dirname->value )
? glob_recursive( dirname->value )
- : list_new( dirs, dirname->value );
+ : list_push_back( dirs, object_new( dirname->value ) );
if ( has_wildcards( basename->value ) )
{
- for ( ; dirs; dirs = dirs->next )
- result = list_append( result, glob1( dirs->string,
- basename->value ) );
+ OBJECT * b = object_new( basename->value );
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob1( list_item( iter ), b ) );
+ object_free( b );
}
else
{
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
string file_string[ 1 ];
string_new( file_string );
/* No wildcard in basename. */
- for ( ; dirs; dirs = dirs->next )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- path->f_dir.ptr = dirs->string;
- path->f_dir.len = strlen( dirs->string );
+ OBJECT * p;
+ path->f_dir.ptr = object_str( list_item( iter ) );
+ path->f_dir.len = strlen( object_str( list_item( iter ) ) );
path_build( path, file_string, 0 );
- result = append_if_exists( result, file_string->value );
+ p = object_new( file_string->value );
+
+ result = append_if_exists( result, p );
+
+ object_free( p );
string_truncate( file_string, 0 );
}
@@ -828,11 +849,15 @@ LIST * glob_recursive( char * pattern )
string_free( dirname );
string_free( basename );
+
+ list_free( dirs );
}
else
{
/** No directory, just a pattern. */
- result = list_append( result, glob1( ".", pattern ) );
+ OBJECT * p = object_new( pattern );
+ result = list_append( result, glob1( constant_dot, p ) );
+ object_free( p );
}
}
@@ -840,12 +865,13 @@ LIST * glob_recursive( char * pattern )
}
-LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
+LIST * builtin_glob_recursive( FRAME * frame, int flags )
{
LIST * result = L0;
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = l->next )
- result = list_append( result, glob_recursive( l->string ) );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob_recursive( object_str( list_item( iter ) ) ) );
return result;
}
@@ -854,26 +880,31 @@ LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
* builtin_match() - MATCH rule, regexp matching.
*/
-LIST * builtin_match( PARSE * parse, FRAME * frame )
+LIST * builtin_match( FRAME * frame, int flags )
{
LIST * l;
LIST * r;
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER l_iter, l_end, r_iter, r_end;
string buf[ 1 ];
string_new( buf );
/* For each pattern */
- for ( l = lol_get( frame->args, 0 ); l; l = l->next )
+ l = lol_get( frame->args, 0 );
+ l_iter = list_begin( l ), l_end = list_end( l );
+ for (; l_iter != l_end; l_iter = list_next( l_iter ) )
{
/* Result is cached and intentionally never freed. */
- regexp * re = regex_compile( l->string );
+ regexp * re = regex_compile( list_item( l_iter ) );
/* For each string to match against. */
- for ( r = lol_get( frame->args, 1 ); r; r = r->next )
+ r = lol_get( frame->args, 1 );
+ r_iter = list_begin( r ), r_end = list_end( r );
+ for ( ; r_iter != r_end; r_iter = list_next( r_iter ) )
{
- if ( regexec( re, r->string ) )
+ if ( regexec( re, object_str( list_item( r_iter ) ) ) )
{
int i;
int top;
@@ -889,7 +920,7 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
for ( i = 1; i <= top; ++i )
{
string_append_range( buf, re->startp[ i ], re->endp[ i ] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -900,41 +931,45 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
return result;
}
-LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
+LIST * builtin_split_by_characters( FRAME * frame, int flags )
{
LIST * l1 = lol_get( frame->args, 0 );
LIST * l2 = lol_get( frame->args, 1 );
- LIST * result = 0;
+ LIST * result = L0;
+
+ string buf[ 1 ];
- char* s = strdup (l1->string);
- char* delimiters = l2->string;
- char* t;
+ const char * delimiters = object_str( list_front( l2 ) );
+ char * t;
- t = strtok (s, delimiters);
- while (t)
+ string_copy( buf, object_str( list_front( l1 ) ) );
+
+ t = strtok( buf->value, delimiters) ;
+ while ( t )
{
- result = list_new(result, newstr(t));
- t = strtok (NULL, delimiters);
+ result = list_push_back( result, object_new( t ) );
+ t = strtok( NULL, delimiters );
}
- free (s);
+ string_free( buf );
return result;
}
-LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
+LIST * builtin_hdrmacro( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Scan file for header filename macro definitions. */
if ( DEBUG_HEADER )
printf( "scanning '%s' for header file macro definitions\n",
- l->string );
+ object_str( list_item( iter ) ) );
macro_headers( t );
}
@@ -955,15 +990,15 @@ static void add_rule_name( void * r_, void * result_ )
RULE * r = (RULE *)r_;
LIST * * result = (LIST * *)result_;
if ( r->exported )
- *result = list_new( *result, copystr( r->name ) );
+ *result = list_push_back( *result, object_copy( r->name ) );
}
-LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
+LIST * builtin_rulenames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 );
if ( source_module->rules )
hashenumerate( source_module->rules, add_rule_name, &result );
@@ -984,36 +1019,17 @@ LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
static void add_hash_key( void * np, void * result_ )
{
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *(char * *)np ) );
+ *result = list_push_back( *result, object_copy( *(OBJECT * *)np ) );
}
-static struct hash * get_running_module_vars()
-{
- struct hash * dummy;
- struct hash * vars = NULL;
- /* Get the global variables pointer (that of the currently running module).
- */
- var_hash_swap( &vars );
- dummy = vars;
- /* Put the global variables pointer in its right place. */
- var_hash_swap( &dummy );
- return vars;
-}
-
-
-LIST * builtin_varnames( PARSE * parse, FRAME * frame )
+LIST * builtin_varnames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
- /* The running module _always_ has its 'variables' member set to NULL due to
- * the way enter_module() and var_hash_swap() work.
- */
- struct hash * vars = source_module == frame->module
- ? get_running_module_vars()
- : source_module->variables;
+ struct hash * vars = source_module->variables;
if ( vars )
hashenumerate( vars, add_hash_key, &result );
@@ -1027,20 +1043,28 @@ LIST * builtin_varnames( PARSE * parse, FRAME * frame )
* Clears all rules and variables from the given module.
*/
-LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
+LIST * builtin_delete_module( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
delete_module( source_module );
return result;
}
-static void unknown_rule( FRAME * frame, char * key, char * module_name, char * rule_name )
+static void unknown_rule( FRAME * frame, const char * key, module_t * module, OBJECT * rule_name )
{
+ const char * module_name = module->name ? object_str( module->name ) : "";
backtrace_line( frame->prev );
- printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
+ if ( module->name )
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"%s.\"\n", key, object_str( rule_name ), object_str( module->name ) );
+ }
+ else
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"\"\n", key, object_str( rule_name ) );
+ }
backtrace( frame->prev );
exit( 1 );
}
@@ -1067,7 +1091,7 @@ static void unknown_rule( FRAME * frame, char * key, char * module_name, char *
* variables.
*/
-LIST * builtin_import( PARSE * parse, FRAME * frame )
+LIST * builtin_import( FRAME * frame, int flags )
{
LIST * source_module_list = lol_get( frame->args, 0 );
LIST * source_rules = lol_get( frame->args, 1 );
@@ -1076,37 +1100,35 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
LIST * localize = lol_get( frame->args, 4 );
module_t * target_module =
- bindmodule( target_module_list ? target_module_list->string : 0 );
+ bindmodule( !list_empty( target_module_list ) ? list_front( target_module_list ) : 0 );
module_t * source_module =
- bindmodule( source_module_list ? source_module_list->string : 0 );
+ bindmodule( !list_empty( source_module_list ) ? list_front( source_module_list ) : 0 );
- LIST * source_name;
- LIST * target_name;
+ LISTITER source_iter = list_begin( source_rules ), source_end = list_end( source_rules );
+ LISTITER target_iter = list_begin( target_rules ), target_end = list_end( target_rules );
- for ( source_name = source_rules, target_name = target_rules;
- source_name && target_name;
- source_name = list_next( source_name ),
- target_name = list_next( target_name ) )
+ for ( ;
+ source_iter != source_end && target_iter != target_end;
+ source_iter = list_next( source_iter ),
+ target_iter = list_next( target_iter ) )
{
- RULE r_;
- RULE * r = &r_;
+ RULE * r;
RULE * imported;
- r_.name = source_name->string;
if ( !source_module->rules ||
- !hashcheck( source_module->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "IMPORT", source_module->name, r_.name );
+ !(r = (RULE *)hash_find( source_module->rules, list_item( source_iter ) ) ) )
+ unknown_rule( frame, "IMPORT", source_module, list_item( source_iter ) );
- imported = import_rule( r, target_module, target_name->string );
- if ( localize )
- imported->module = target_module;
+ imported = import_rule( r, target_module, list_item( target_iter ) );
+ if ( !list_empty( localize ) )
+ rule_localize( imported, target_module );
/* This rule is really part of some other module. Just refer to it here,
* but do not let it out.
*/
imported->exported = 0;
}
- if ( source_name || target_name )
+ if ( source_iter != source_end || target_iter != target_end )
{
backtrace_line( frame->prev );
printf( "import error: length of source and target rule name lists don't match!\n" );
@@ -1131,20 +1153,19 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
* is issued.
*/
-LIST * builtin_export( PARSE * parse, FRAME * frame )
+LIST * builtin_export( FRAME * frame, int flags )
{
LIST * module_list = lol_get( frame->args, 0 );
LIST * rules = lol_get( frame->args, 1 );
- module_t * m = bindmodule( module_list ? module_list->string : 0 );
+ module_t * m = bindmodule( !list_empty( module_list ) ? list_front( module_list ) : 0 );
- for ( ; rules; rules = list_next( rules ) )
+ LISTITER iter = list_begin( rules ), end = list_end( rules );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- RULE r_;
- RULE * r = &r_;
- r_.name = rules->string;
+ RULE * r;
- if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "EXPORT", m->name, r_.name );
+ if ( !m->rules || !(r = (RULE *)hash_find( m->rules, list_item( iter ) ) ) )
+ unknown_rule( frame, "EXPORT", m, list_item( iter ) );
r->exported = 1;
}
@@ -1157,12 +1178,12 @@ LIST * builtin_export( PARSE * parse, FRAME * frame )
* indicated for a given procedure in debug output or an error backtrace.
*/
-static void get_source_line( PARSE * procedure, char * * file, int * line )
+static void get_source_line( FRAME * frame, const char * * file, int * line )
{
- if ( procedure )
+ if ( frame->file )
{
- char * f = procedure->file;
- int l = procedure->line;
+ const char * f = object_str( frame->file );
+ int l = frame->line;
if ( !strcmp( f, "+" ) )
{
f = "jambase.c";
@@ -1179,12 +1200,12 @@ static void get_source_line( PARSE * procedure, char * * file, int * line )
}
-void print_source_line( PARSE * p )
+void print_source_line( FRAME * frame )
{
- char * file;
+ const char * file;
int line;
- get_source_line( p, &file, &line );
+ get_source_line( frame, &file, &line );
if ( line < 0 )
printf( "(builtin):" );
else
@@ -1205,7 +1226,7 @@ void backtrace_line( FRAME * frame )
}
else
{
- print_source_line( frame->procedure );
+ print_source_line( frame );
printf( " in %s\n", frame->rulename );
}
}
@@ -1231,23 +1252,31 @@ void backtrace( FRAME * frame )
* period.
*/
-LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
+LIST * builtin_backtrace( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : ( (unsigned int)(-1) >> 1 ) ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : (int)( (unsigned int)(-1) >> 1 ) ;
LIST * result = L0;
for ( ; ( frame = frame->prev ) && levels ; --levels )
{
- char * file;
+ const char * file;
int line;
char buf[32];
- get_source_line( frame->procedure, &file, &line );
+ string module_name[1];
+ get_source_line( frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
- result = list_new( result, newstr( frame->module->name ) );
- result = list_new( result, newstr( frame->rulename ) );
+ string_new( module_name );
+ if ( frame->module->name )
+ {
+ string_append( module_name, object_str( frame->module->name ) );
+ string_append( module_name, "." );
+ }
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
+ result = list_push_back( result, object_new( module_name->value ) );
+ result = list_push_back( result, object_new( frame->rulename ) );
+ string_free( module_name );
}
return result;
}
@@ -1265,10 +1294,10 @@ LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
* behavior.
*/
-LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
+LIST * builtin_caller_module( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : 0 ;
int i;
for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
@@ -1276,16 +1305,8 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
if ( frame->module == root_module() )
return L0;
-
- {
- LIST * result;
- string name;
- string_copy( &name, frame->module->name );
- string_pop_back( &name );
- result = list_new( L0, newstr(name.value) );
- string_free( &name );
- return result;
- }
+ else
+ return list_new( object_copy( frame->module->name ) );
}
@@ -1295,7 +1316,7 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
* Usage: pwd = [ PWD ] ;
*/
-LIST * builtin_pwd( PARSE * parse, FRAME * frame )
+LIST * builtin_pwd( FRAME * frame, int flags )
{
return pwd();
}
@@ -1305,13 +1326,14 @@ LIST * builtin_pwd( PARSE * parse, FRAME * frame )
* Adds targets to the list of target that jam will attempt to update.
*/
-LIST * builtin_update( PARSE * parse, FRAME * frame )
+LIST * builtin_update( FRAME * frame, int flags )
{
- LIST * result = list_copy( L0, targets_to_update() );
+ LIST * result = list_copy( targets_to_update() );
LIST * arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
clear_targets_to_update();
- for ( ; arg1; arg1 = list_next( arg1 ) )
- mark_target_for_updating( newstr( arg1->string ) );
+ for ( ; iter != end; iter = list_next( iter ) )
+ mark_target_for_updating( object_copy( list_item( iter ) ) );
return result;
}
@@ -1325,34 +1347,30 @@ int last_update_now_status;
Third parameter, if non-empty, specifies that the -n option should have
no effect -- that is, all out-of-date targets should be rebuild.
*/
-LIST * builtin_update_now( PARSE * parse, FRAME * frame )
+LIST * builtin_update_now( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * log = lol_get( frame->args, 1 );
- LIST * force = lol_get (frame->args, 2);
- LIST * continue_ = lol_get(frame->args, 3);
- int status = 0;
- int original_stdout;
- int original_stderr;
- int n;
- int targets_count;
- const char** targets2;
- int i;
- int original_noexec;
- int original_quitquick;
+ LIST * force = lol_get( frame->args, 2 );
+ LIST * continue_ = lol_get( frame->args, 3 );
+ int status;
+ int original_stdout = 0;
+ int original_stderr = 0;
+ int original_noexec = 0;
+ int original_quitquick = 0;
- if (log)
+ if ( !list_empty( log ) )
{
- int fd = atoi(log->string);
+ int fd = atoi( object_str( list_front( log ) ) );
/* Redirect stdout and stderr, temporary, to the log file. */
- original_stdout = dup (0);
- original_stderr = dup (1);
- dup2 (fd, 0);
- dup2 (fd, 1);
+ original_stdout = dup( 0 );
+ original_stderr = dup( 1 );
+ dup2 ( fd, 0 );
+ dup2 ( fd, 1 );
}
- if (force)
+ if ( !list_empty( force ) )
{
original_noexec = globs.noexec;
globs.noexec = 0;
@@ -1360,95 +1378,83 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame )
globs.quitquick = 0;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
original_quitquick = globs.quitquick;
globs.quitquick = 0;
}
- targets_count = list_length( targets );
- targets2 = (const char * *)BJAM_MALLOC( targets_count * sizeof( char * ) );
- for (i = 0 ; targets; targets = list_next( targets ) )
- targets2[ i++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow);
- free( targets );
+ status = make( targets, anyhow );
- if (force)
+ if ( !list_empty( force ) )
{
globs.noexec = original_noexec;
globs.quitquick = original_quitquick;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
globs.quitquick = original_quitquick;
}
- if (log)
+ if ( !list_empty( log ) )
{
/* Flush whatever stdio might have buffered, while descriptions
0 and 1 still refer to the log file. */
- fflush (stdout);
- fflush (stderr);
- dup2 (original_stdout, 0);
- dup2 (original_stderr, 1);
- close (original_stdout);
- close (original_stderr);
+ fflush( stdout );
+ fflush( stderr );
+ dup2( original_stdout, 0 );
+ dup2( original_stderr, 1 );
+ close( original_stdout );
+ close( original_stderr );
}
last_update_now_status = status;
- if (status == 0)
- return list_new (L0, newstr ("ok"));
+ if ( status == 0 )
+ return list_new( object_copy( constant_ok ) );
else
return L0;
}
-LIST * builtin_search_for_target( PARSE * parse, FRAME * frame )
-{
- LIST * arg1 = lol_get( frame->args, 0 );
- LIST * arg2 = lol_get( frame->args, 1 );
- TARGET * t = search_for_target( arg1->string, arg2 );
- return list_new( L0, t->name );
-}
-
-LIST * builtin_import_module( PARSE * parse, FRAME * frame )
+LIST * builtin_import_module( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
LIST * arg2 = lol_get( frame->args, 1 );
- module_t * m = arg2 ? bindmodule( arg2->string ) : root_module();
+ module_t * m = !list_empty( arg2 ) ? bindmodule( list_front( arg2 ) ) : root_module();
import_module( arg1, m );
return L0;
}
-LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
+LIST * builtin_imported_modules( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
- return imported_modules( bindmodule( arg0 ? arg0->string : 0 ) );
+ return imported_modules( bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 ) );
}
-LIST * builtin_instance( PARSE * parse, FRAME * frame )
+LIST * builtin_instance( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
LIST * arg2 = lol_get( frame->args, 1 );
- module_t * const instance = bindmodule( arg1->string );
- module_t * const class_module = bindmodule( arg2->string );
+ module_t * const instance = bindmodule( list_front( arg1 ) );
+ module_t * const class_module = bindmodule( list_front( arg2 ) );
instance->class_module = class_module;
+ module_set_fixed_variables( instance, class_module->num_fixed_variables );
return L0;
}
-LIST * builtin_sort( PARSE * parse, FRAME * frame )
+LIST * builtin_sort( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
return list_sort( arg1 );
}
-LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
+LIST * builtin_normalize_path( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
@@ -1468,7 +1474,8 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
/* Number of '..' elements seen and not processed yet. */
int dotdots = 0;
int rooted = 0;
- char * result = 0;
+ OBJECT * result = 0;
+ LISTITER arg_iter = list_begin( arg ), arg_end = list_end( arg );
/* Make a copy of input: we should not change it. Prepend a '/' before it as
* a guard for the algorithm later on and remember whether it was originally
@@ -1476,16 +1483,16 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
string_new( in );
string_push_back( in, '/' );
- for ( ; arg; arg = list_next( arg ) )
+ for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) )
{
- if ( arg->string[ 0 ] != '\0' )
+ if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' )
{
if ( in->size == 1 )
- rooted = ( ( arg->string[ 0 ] == '/' ) ||
- ( arg->string[ 0 ] == '\\' ) );
+ rooted = ( ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) ||
+ ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' ) );
else
string_append( in, "/" );
- string_append( in, arg->string );
+ string_append( in, object_str( list_item( arg_iter ) ) );
}
}
@@ -1544,7 +1551,12 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
if ( dotdots )
{
- if ( rooted ) return L0;
+ if ( rooted )
+ {
+ string_free( out );
+ string_free( in );
+ return L0;
+ }
do
string_append( out, "/.." );
while ( --dotdots );
@@ -1561,34 +1573,32 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
* the original path was rooted and we have an empty path we need to add
* back the '/'.
*/
- result = newstr( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
+ result = object_new( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
string_free( out );
string_free( in );
- return list_new( 0, result );
+ return list_new( result );
}
-LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
+ new_rule_body( module, np->name, np->procedure, 1 );
}
else
{
backtrace_line( frame->prev );
- printf( "error: no native rule \"%s\" defined in module \"%s\"\n",
- n.name, module->name );
+ printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
+ object_str( list_front( rule_name ) ), object_str( module->name ) );
backtrace( frame->prev );
exit( 1 );
}
@@ -1596,40 +1606,39 @@ LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
}
-LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_has_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
LIST * version = lol_get( frame->args, 2 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- int expected_version = atoi( version->string );
+ int expected_version = atoi( object_str( list_front( version ) ) );
if ( np->version == expected_version )
- return list_new( 0, newstr( "true" ) );
+ return list_new( object_copy( constant_true ) );
}
return L0;
}
-LIST * builtin_user_module( PARSE * parse, FRAME * frame )
+LIST * builtin_user_module( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
- for ( ; module_name; module_name = module_name->next )
+ LISTITER iter = list_begin( module_name ), end = list_end( module_name );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- module_t * m = bindmodule( module_name->string );
+ module_t * m = bindmodule( list_item( iter ) );
m->user_module = 1;
}
return L0;
}
-LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
+LIST * builtin_nearest_user_location( FRAME * frame, int flags )
{
FRAME * nearest_user_frame =
frame->module->user_module ? frame : frame->prev_user;
@@ -1637,33 +1646,33 @@ LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
return L0;
{
- LIST * result = 0;
- char * file;
+ LIST * result = L0;
+ const char * file;
int line;
char buf[32];
- get_source_line( nearest_user_frame->procedure, &file, &line );
+ get_source_line( nearest_user_frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
return result;
}
}
-LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
+LIST * builtin_check_if_file( FRAME * frame, int flags )
{
LIST * name = lol_get( frame->args, 0 );
- return file_is_file( name->string ) == 1
- ? list_new( 0, newstr( "true" ) )
+ return file_is_file( list_front( name ) ) == 1
+ ? list_new( object_copy( constant_true ) )
: L0 ;
}
-LIST * builtin_md5( PARSE * parse, FRAME * frame )
+LIST * builtin_md5( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- char* s = l->string;
+ const char* s = object_str( list_front( l ) );
md5_state_t state;
md5_byte_t digest[16];
@@ -1671,36 +1680,36 @@ LIST * builtin_md5( PARSE * parse, FRAME * frame )
int di;
- md5_init(&state);
- md5_append(&state, (const md5_byte_t *)s, strlen(s));
- md5_finish(&state, digest);
+ md5_init( &state );
+ md5_append( &state, (const md5_byte_t *)s, strlen(s) );
+ md5_finish( &state, digest );
for (di = 0; di < 16; ++di)
- sprintf(hex_output + di * 2, "%02x", digest[di]);
+ sprintf( hex_output + di * 2, "%02x", digest[di] );
- return list_new (0, newstr(hex_output));
+ return list_new( object_new( hex_output ) );
}
-LIST *builtin_file_open( PARSE *parse, FRAME *frame )
+LIST *builtin_file_open( FRAME * frame, int flags )
{
- char* name = lol_get(frame->args, 0)->string;
- char* mode = lol_get(frame->args, 1)->string;
+ const char * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ const char * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
int fd;
char buffer[sizeof("4294967295")];
- if (strcmp(mode, "w") == 0)
+ if ( strcmp(mode, "w") == 0 )
{
- fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
}
else
{
- fd = open(name, O_RDONLY);
+ fd = open( name, O_RDONLY );
}
if (fd != -1)
{
- sprintf(buffer, "%d", fd);
- return list_new(L0, newstr(buffer));
+ sprintf( buffer, "%d", fd );
+ return list_new( object_new( buffer ) );
}
else
{
@@ -1708,52 +1717,53 @@ LIST *builtin_file_open( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_pad( PARSE *parse, FRAME *frame )
+LIST *builtin_pad( FRAME * frame, int flags )
{
- char *string = lol_get(frame->args, 0)->string;
- char *width_s = lol_get(frame->args, 1)->string;
+ OBJECT * string = list_front( lol_get( frame->args, 0 ) );
+ const char * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
- int current = strlen (string);
- int desired = atoi(width_s);
+ int current = strlen( object_str( string ) );
+ int desired = atoi( width_s );
if (current >= desired)
- return list_new (L0, string);
+ return list_new( object_copy( string ) );
else
{
- char *buffer = malloc (desired + 1);
+ char * buffer = BJAM_MALLOC( desired + 1 );
int i;
- LIST *result;
+ LIST * result;
- strcpy (buffer, string);
- for (i = current; i < desired; ++i)
+ strcpy( buffer, object_str( string ) );
+ for ( i = current; i < desired; ++i )
buffer[i] = ' ';
buffer[desired] = '\0';
- result = list_new (L0, newstr (buffer));
- free (buffer);
+ result = list_new( object_new( buffer ) );
+ BJAM_FREE( buffer );
return result;
}
}
-LIST *builtin_precious( PARSE *parse, FRAME *frame )
+LIST *builtin_precious( FRAME * frame, int flags )
{
- LIST* targets = lol_get(frame->args, 0);
+ LIST * targets = lol_get(frame->args, 0);
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET* t = bindtarget (targets->string);
+ TARGET* t = bindtarget( list_item( iter ) );
t->flags |= T_FLAG_PRECIOUS;
}
return L0;
}
-LIST *builtin_self_path( PARSE *parse, FRAME *frame )
+LIST *builtin_self_path( FRAME * frame, int flags )
{
- extern char *saved_argv0;
- char *p = executable_path (saved_argv0);
- if (p)
+ extern const char * saved_argv0;
+ char * p = executable_path( saved_argv0 );
+ if ( p )
{
- LIST* result = list_new (0, newstr (p));
- free(p);
+ LIST* result = list_new( object_new( p ) );
+ free( p );
return result;
}
else
@@ -1762,13 +1772,13 @@ LIST *builtin_self_path( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_makedir( PARSE *parse, FRAME *frame )
+LIST *builtin_makedir( FRAME * frame, int flags )
{
- LIST *path = lol_get(frame->args, 0);
+ LIST * path = lol_get( frame->args, 0 );
- if (file_mkdir(path->string) == 0)
+ if ( file_mkdir( object_str( list_front( path ) ) ) == 0 )
{
- LIST *result = list_new (0, newstr(path->string));
+ LIST * result = list_new( object_copy( list_front( path ) ) );
return result;
}
else
@@ -1779,13 +1789,13 @@ LIST *builtin_makedir( PARSE *parse, FRAME *frame )
#ifdef HAVE_PYTHON
-LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_python_import_rule( FRAME * frame, int flags )
{
static int first_time = 1;
- char * python_module = lol_get( frame->args, 0 )->string;
- char * python_function = lol_get( frame->args, 1 )->string;
- char * jam_module = lol_get( frame->args, 2 )->string;
- char * jam_rule = lol_get( frame->args, 3 )->string;
+ const char * python_module = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ const char * python_function = object_str( list_front( lol_get( frame->args, 1 ) ) );
+ OBJECT * jam_module = list_front( lol_get( frame->args, 2 ) );
+ OBJECT * jam_rule = list_front( lol_get( frame->args, 3 ) );
PyObject * pName;
PyObject * pModule;
@@ -1799,29 +1809,19 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
*/
LIST * extra = 0;
module_t * outer_module = frame->module;
+ LISTITER iter, end;
first_time = 0;
- if ( outer_module != root_module() )
- {
- exit_module( outer_module );
- enter_module( root_module() );
- }
-
- extra = var_get( "EXTRA_PYTHONPATH" );
-
- if ( outer_module != root_module() )
- {
- exit_module( root_module() );
- enter_module( outer_module );
- }
+ extra = var_get( root_module(), constant_extra_pythonpath );
- for ( ; extra; extra = extra->next )
+ iter = list_begin( extra ), end = list_end( extra );
+ for ( ; iter != end; iter = list_next( iter ) )
{
string buf[ 1 ];
string_new( buf );
string_append( buf, "import sys\nsys.path.append(\"" );
- string_append( buf, extra->string );
+ string_append( buf, object_str( list_item( iter ) ) );
string_append( buf, "\")\n" );
PyRun_SimpleString( buf->value );
string_free( buf );
@@ -1840,12 +1840,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
if ( pFunc && PyCallable_Check( pFunc ) )
{
module_t * m = bindmodule( jam_module );
- RULE * r = bindrule( jam_rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( pFunc );
-
- r->python_function = pFunc;
+ new_rule_body( m, jam_rule, function_python( pFunc, 0 ), 0 );
}
else
{
@@ -1866,7 +1861,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
#endif
-void lol_build( LOL * lol, char * * elements )
+void lol_build( LOL * lol, const char * * elements )
{
LIST * l = L0;
lol_init( lol );
@@ -1880,7 +1875,7 @@ void lol_build( LOL * lol, char * * elements )
}
else
{
- l = list_new( l, newstr( *elements ) );
+ l = list_push_back( l, object_new( *elements ) );
}
++elements;
}
@@ -1900,22 +1895,21 @@ void lol_build( LOL * lol, char * * elements )
PyObject* bjam_call( PyObject * self, PyObject * args )
{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
- char * rulename;
+ FRAME inner[ 1 ];
+ LIST * result;
+ PARSE * p;
+ OBJECT * rulename;
/* Build up the list of arg lists. */
frame_init( inner );
inner->prev = 0;
inner->prev_user = 0;
- inner->module = bindmodule( "python_interface" );
- inner->procedure = 0;
+ inner->module = bindmodule( constant_python_interface );
/* Extract the rule name and arguments from 'args'. */
/* PyTuple_GetItem returns borrowed reference. */
- rulename = PyString_AsString( PyTuple_GetItem( args, 0 ) );
+ rulename = object_new( PyString_AsString( PyTuple_GetItem( args, 0 ) ) );
{
int i = 1;
int size = PyTuple_Size( args );
@@ -1924,7 +1918,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
PyObject * a = PyTuple_GetItem( args, i );
if ( PyString_Check( a ) )
{
- lol_add( inner->args, list_new( 0, newstr(
+ lol_add( inner->args, list_new( object_new(
PyString_AsString( a ) ) ) );
}
else if ( PySequence_Check( a ) )
@@ -1942,7 +1936,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
printf( "Invalid parameter type passed from Python\n" );
exit( 1 );
}
- l = list_new( l, newstr( s ) );
+ l = list_push_back( l, object_new( s ) );
Py_DECREF( e );
}
lol_add( inner->args, l );
@@ -1951,6 +1945,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
}
result = evaluate_rule( rulename, inner );
+ object_free( rulename );
frame_free( inner );
@@ -1958,10 +1953,10 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
{
PyObject * pyResult = PyList_New( list_length( result ) );
int i = 0;
- while ( result )
+ LISTITER iter = list_begin( result ), end = list_end( result );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- PyList_SetItem( pyResult, i, PyString_FromString( result->string ) );
- result = list_next( result );
+ PyList_SetItem( pyResult, i, PyString_FromString( object_str( list_item( iter ) ) ) );
i += 1;
}
list_free( result );
@@ -1988,6 +1983,8 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
PyObject * bjam_signature = NULL;
module_t * m;
RULE * r;
+ OBJECT * module_name;
+ OBJECT * rule_name;
if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
&module, &rule, &func, &bjam_signature ) )
@@ -2000,29 +1997,15 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
return NULL;
}
- m = bindmodule( *module ? module : 0 );
- r = bindrule( rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( func );
-
- r->python_function = func;
- r->arguments = 0;
-
- if (bjam_signature)
+ module_name = *module ? object_new( module ) : 0;
+ m = bindmodule( module_name );
+ if( module_name )
{
- argument_list * arg_list = args_new();
- Py_ssize_t i;
-
- Py_ssize_t s = PySequence_Size (bjam_signature);
- for (i = 0; i < s; ++i)
- {
- PyObject* v = PySequence_GetItem (bjam_signature, i);
- lol_add(arg_list->data, list_from_python (v));
- Py_DECREF(v);
- }
- r->arguments = arg_list;
+ object_free( module_name );
}
+ rule_name = object_new( rule );
+ new_rule_body( m, rule_name, function_python( func, bjam_signature ), 0 );
+ object_free( rule_name );
Py_INCREF( Py_None );
return Py_None;
@@ -2048,6 +2031,8 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
LIST * bindlist = L0;
int n;
int i;
+ OBJECT * name_str;
+ FUNCTION * body_func;
if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
&PyList_Type, &bindlist_python, &flags ) )
@@ -2063,10 +2048,14 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
"bind list has non-string type" );
return NULL;
}
- bindlist = list_new( bindlist, PyString_AsString( next ) );
+ bindlist = list_push_back( bindlist, object_new( PyString_AsString( next ) ) );
}
- new_rule_actions( root_module(), name, newstr( body ), bindlist, flags );
+ name_str = object_new( name );
+ body_func = function_compile_actions( body, constant_builtin, -1 );
+ new_rule_actions( root_module(), name_str, body_func, bindlist, flags );
+ function_free( body_func );
+ object_free( name_str );
Py_INCREF( Py_None );
return Py_None;
@@ -2083,17 +2072,20 @@ PyObject * bjam_variable( PyObject * self, PyObject * args )
LIST * value;
PyObject * result;
int i;
+ OBJECT * varname;
+ LISTITER iter, end;
if ( !PyArg_ParseTuple( args, "s", &name ) )
return NULL;
- enter_module( root_module() );
- value = var_get( name );
- exit_module( root_module() );
+ varname = object_new( name );
+ value = var_get( root_module(), varname );
+ object_free( varname );
+ iter = list_begin( value ), end = list_end( value );
result = PyList_New( list_length( value ) );
- for ( i = 0; value; value = list_next( value ), ++i )
- PyList_SetItem( result, i, PyString_FromString( value->string ) );
+ for ( i = 0; iter != end; iter = list_next( iter ), ++i )
+ PyList_SetItem( result, i, PyString_FromString( object_str( list_item( iter ) ) ) );
return result;
}
@@ -2106,19 +2098,28 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
for ( ; f = f->prev; )
{
- PyObject * tuple = PyTuple_New( 4 );
- char * file;
- int line;
- char buf[ 32 ];
+ PyObject * tuple = PyTuple_New( 4 );
+ const char * file;
+ int line;
+ char buf[ 32 ];
+ string module_name[1];
- get_source_line( f->procedure, &file, &line );
+ get_source_line( f, &file, &line );
sprintf( buf, "%d", line );
+ string_new( module_name );
+ if ( f->module->name )
+ {
+ string_append( module_name, object_str( f->module->name ) );
+ string_append( module_name, "." );
+ }
/* PyTuple_SetItem steals reference. */
PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
- PyTuple_SetItem( tuple, 2, PyString_FromString( f->module->name ) );
- PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+ PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
+ PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+
+ string_free( module_name );
PyList_Append( result, tuple );
Py_DECREF( tuple );
@@ -2128,9 +2129,10 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
PyObject * bjam_caller( PyObject * self, PyObject * args )
{
- PyObject *result = PyString_FromString(
- frame_before_python_call->prev->module->name);
- return result;
+ const char * s = frame_before_python_call->prev->module->name ?
+ object_str( frame_before_python_call->prev->module->name ) :
+ "";
+ return PyString_FromString( s );
}
#endif /* #ifdef HAVE_PYTHON */
@@ -2189,7 +2191,7 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
* should Windows ever 'fix' this feature.
* (03.06.2008.) (Jurko)
*/
- static FILE * windows_popen_wrapper( char * command, char * mode )
+ static FILE * windows_popen_wrapper( const char * command, const char * mode )
{
int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
string quoted_command;
@@ -2214,18 +2216,18 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
#endif
-static char * rtrim(char *s)
+static char * rtrim( char * s )
{
- char *p = s;
- while(*p) ++p;
- for(--p; p >= s && isspace(*p); *p-- = 0);
+ char * p = s;
+ while ( *p ) ++p;
+ for ( --p; p >= s && isspace( *p ); *p-- = 0 );
return s;
}
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
LIST * command = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
string s;
int ret;
char buffer[ 1024 ];
@@ -2239,17 +2241,17 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
{
int a = 1;
LIST * arg = lol_get( frame->args, a );
- while ( arg )
+ while ( !list_empty( arg ) )
{
- if ( strcmp( "exit-status", arg->string ) == 0 )
+ if ( strcmp( "exit-status", object_str( list_front( arg ) ) ) == 0 )
{
exit_status_opt = 1;
}
- else if ( strcmp( "no-output", arg->string ) == 0 )
+ else if ( strcmp( "no-output", object_str( list_front( arg ) ) ) == 0 )
{
no_output_opt = 1;
}
- else if ( strcmp("strip-eol", arg->string) == 0 )
+ else if ( strcmp("strip-eol", object_str( list_front( arg ) ) ) == 0 )
{
strip_eol_opt = 1;
}
@@ -2263,7 +2265,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
*/
fflush( NULL );
- p = popen( command->string, "r" );
+ p = popen( object_str( list_front( command ) ), "r" );
if ( p == NULL )
return L0;
@@ -2283,7 +2285,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
exit_status = pclose( p );
/* The command output is returned first. */
- result = list_new( L0, newstr( s.value ) );
+ result = list_new( object_new( s.value ) );
string_free( &s );
/* The command exit result next. */
@@ -2294,7 +2296,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
else
exit_status = -1;
sprintf( buffer, "%d", exit_status );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
}
return result;
@@ -2302,7 +2304,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
#else /* #ifdef HAVE_POPEN */
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
return L0;
}
diff --git a/tools/build/v2/engine/builtins.h b/tools/build/v2/engine/builtins.h
index 5fed07c968..b8c086fb4f 100644
--- a/tools/build/v2/engine/builtins.h
+++ b/tools/build/v2/engine/builtins.h
@@ -21,47 +21,46 @@ void init_property_set();
void init_sequence();
void init_order();
-LIST *builtin_calc( PARSE *parse, FRAME *args );
-LIST *builtin_depends( PARSE *parse, FRAME *args );
-LIST *builtin_rebuilds( PARSE *parse, FRAME *args );
-LIST *builtin_echo( PARSE *parse, FRAME *args );
-LIST *builtin_exit( PARSE *parse, FRAME *args );
-LIST *builtin_flags( PARSE *parse, FRAME *args );
-LIST *builtin_glob( PARSE *parse, FRAME *args );
-LIST *builtin_glob_recursive( PARSE *parse, FRAME *frame );
-LIST *builtin_subst( PARSE *parse, FRAME *args );
-LIST *builtin_match( PARSE *parse, FRAME *args );
-LIST *builtin_split_by_characters( PARSE *parse, FRAME *args );
-LIST *builtin_hdrmacro( PARSE *parse, FRAME *args );
-LIST *builtin_rulenames( PARSE *parse, FRAME *args );
-LIST *builtin_varnames( PARSE *parse, FRAME *args );
-LIST *builtin_delete_module( PARSE *parse, FRAME *args );
-LIST *builtin_import( PARSE *parse, FRAME *args );
-LIST *builtin_export( PARSE *parse, FRAME *args );
-LIST *builtin_caller_module( PARSE *parse, FRAME *args );
-LIST *builtin_backtrace( PARSE *parse, FRAME *args );
-LIST *builtin_pwd( PARSE *parse, FRAME *args );
-LIST *builtin_update( PARSE *parse, FRAME *args );
-LIST *builtin_update_now( PARSE *parse, FRAME *args );
-LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
-LIST *builtin_import_module( PARSE *parse, FRAME *args );
-LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
-LIST *builtin_instance( PARSE *parse, FRAME *frame );
-LIST *builtin_sort( PARSE *parse, FRAME *frame );
-LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
-LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_has_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_user_module( PARSE *parse, FRAME *frame );
-LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
-LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
-LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_shell( PARSE *parse, FRAME *frame );
-LIST *builtin_md5( PARSE *parse, FRAME *frame );
-LIST *builtin_file_open( PARSE *parse, FRAME *frame );
-LIST *builtin_pad( PARSE *parse, FRAME *frame );
-LIST *builtin_precious( PARSE *parse, FRAME *frame );
-LIST *builtin_self_path( PARSE *parse, FRAME *frame );
-LIST *builtin_makedir( PARSE *parse, FRAME *frame );
+LIST *builtin_calc( FRAME * frame, int flags );
+LIST *builtin_depends( FRAME * frame, int flags );
+LIST *builtin_rebuilds( FRAME * frame, int flags );
+LIST *builtin_echo( FRAME * frame, int flags );
+LIST *builtin_exit( FRAME * frame, int flags );
+LIST *builtin_flags( FRAME * frame, int flags );
+LIST *builtin_glob( FRAME * frame, int flags );
+LIST *builtin_glob_recursive( FRAME * frame, int flags );
+LIST *builtin_subst( FRAME * frame, int flags );
+LIST *builtin_match( FRAME * frame, int flags );
+LIST *builtin_split_by_characters( FRAME * frame, int flags );
+LIST *builtin_hdrmacro( FRAME * frame, int flags );
+LIST *builtin_rulenames( FRAME * frame, int flags );
+LIST *builtin_varnames( FRAME * frame, int flags );
+LIST *builtin_delete_module( FRAME * frame, int flags );
+LIST *builtin_import( FRAME * frame, int flags );
+LIST *builtin_export( FRAME * frame, int flags );
+LIST *builtin_caller_module( FRAME * frame, int flags );
+LIST *builtin_backtrace( FRAME * frame, int flags );
+LIST *builtin_pwd( FRAME * frame, int flags );
+LIST *builtin_update( FRAME * frame, int flags );
+LIST *builtin_update_now( FRAME * frame, int flags );
+LIST *builtin_import_module( FRAME * frame, int flags );
+LIST *builtin_imported_modules( FRAME * frame, int flags );
+LIST *builtin_instance( FRAME * frame, int flags );
+LIST *builtin_sort( FRAME * frame, int flags );
+LIST *builtin_normalize_path( FRAME * frame, int flags );
+LIST *builtin_native_rule( FRAME * frame, int flags );
+LIST *builtin_has_native_rule( FRAME * frame, int flags );
+LIST *builtin_user_module( FRAME * frame, int flags );
+LIST *builtin_nearest_user_location( FRAME * frame, int flags );
+LIST *builtin_check_if_file( FRAME * frame, int flags );
+LIST *builtin_python_import_rule( FRAME * frame, int flags );
+LIST *builtin_shell( FRAME * frame, int flags );
+LIST *builtin_md5( FRAME * frame, int flags );
+LIST *builtin_file_open( FRAME * frame, int flags );
+LIST *builtin_pad( FRAME * frame, int flags );
+LIST *builtin_precious( FRAME * frame, int flags );
+LIST *builtin_self_path( FRAME * frame, int flags );
+LIST *builtin_makedir( FRAME * frame, int flags );
void backtrace( FRAME *frame );
extern int last_update_now_status;
diff --git a/tools/build/v2/engine/class.c b/tools/build/v2/engine/class.c
index ff4ec56807..8871d1113b 100644
--- a/tools/build/v2/engine/class.c
+++ b/tools/build/v2/engine/class.c
@@ -7,7 +7,7 @@
#include "variable.h"
#include "frames.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "hash.h"
@@ -17,28 +17,28 @@ static struct hash * classes = 0;
static void check_defined( LIST * class_names )
{
- for ( ; class_names; class_names = class_names->next )
+ LISTITER iter = list_begin( class_names ), end = list_end( class_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * * p = &class_names->string;
- if ( !hashcheck( classes, (HASHDATA * *)&p ) )
+ if ( !hash_find( classes, list_item( iter ) ) )
{
- printf( "Class %s is not defined\n", class_names->string );
+ printf( "Class %s is not defined\n", object_str( list_item( iter ) ) );
abort();
}
}
}
-static char * class_module_name( char * declared_name )
+static OBJECT * class_module_name( OBJECT * declared_name )
{
string name[ 1 ];
- char * result;
+ OBJECT * result;
string_new( name );
string_append( name, "class@" );
- string_append( name, declared_name );
+ string_append( name, object_str( declared_name ) );
- result = newstr( name->value );
+ result = object_new( name->value );
string_free( name );
return result;
@@ -47,7 +47,7 @@ static char * class_module_name( char * declared_name )
struct import_base_data
{
- char * base_name;
+ OBJECT * base_name;
module_t * base_module;
module_t * class_module;
};
@@ -60,14 +60,19 @@ static void import_base_rule( void * r_, void * d_ )
RULE * ir2;
struct import_base_data * d = (struct import_base_data *)d_;
string qualified_name[ 1 ];
+ OBJECT * qname;
string_new ( qualified_name );
- string_append ( qualified_name, d->base_name );
+ string_append ( qualified_name, object_str( d->base_name ) );
string_push_back( qualified_name, '.' );
- string_append ( qualified_name, r->name );
+ string_append ( qualified_name, object_str( r->name ) );
+
+ qname = object_new( qualified_name->value );
ir1 = import_rule( r, d->class_module, r->name );
- ir2 = import_rule( r, d->class_module, qualified_name->value );
+ ir2 = import_rule( r, d->class_module, qname );
+
+ object_free( qname );
/* Copy 'exported' flag. */
ir1->exported = ir2->exported = r->exported;
@@ -75,7 +80,10 @@ static void import_base_rule( void * r_, void * d_ )
/* If we are importing a class method, localize it. */
if ( ( r->module == d->base_module ) || ( r->module->class_module &&
( r->module->class_module == d->base_module ) ) )
- ir1->module = ir2->module = d->class_module;
+ {
+ rule_localize( ir1, d->class_module );
+ rule_localize( ir2, d->class_module );
+ }
string_free( qualified_name );
}
@@ -87,55 +95,73 @@ static void import_base_rule( void * r_, void * d_ )
* marked as exported.
*/
-static void import_base_rules( module_t * class, char * base )
+static void import_base_rules( module_t * class_, OBJECT * base )
{
- module_t * base_module = bindmodule( class_module_name( base ) );
+ OBJECT * module_name = class_module_name( base );
+ module_t * base_module = bindmodule( module_name );
+ LIST * imported;
struct import_base_data d;
d.base_name = base;
d.base_module = base_module;
- d.class_module = class;
+ d.class_module = class_;
+ object_free( module_name );
if ( base_module->rules )
hashenumerate( base_module->rules, import_base_rule, &d );
- import_module( imported_modules( base_module ), class );
+ imported = imported_modules( base_module );
+ import_module( imported, class_ );
+ list_free( imported );
}
-char * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
{
- char * name = class_module_name( xname->string );
- char * * pp = &xname->string;
+ OBJECT * name = class_module_name( list_front( xname ) );
+ OBJECT * * pp;
module_t * class_module = 0;
module_t * outer_module = frame->module;
+ int found;
+ LISTITER iter, end;
if ( !classes )
- classes = hashinit( sizeof( char * ), "classes" );
+ classes = hashinit( sizeof( OBJECT * ), "classes" );
- if ( hashcheck( classes, (HASHDATA * *)&pp ) )
+ pp = (OBJECT * *)hash_insert( classes, list_front( xname ), &found );
+ if ( !found )
{
- printf( "Class %s already defined\n", xname->string );
- abort();
+ *pp = object_copy( list_front( xname ) );
}
else
{
- hashenter( classes, (HASHDATA * *)&pp );
+ printf( "Class %s already defined\n", object_str( list_front( xname ) ) );
+ abort();
}
check_defined( bases );
class_module = bindmodule( name );
- exit_module( outer_module );
- enter_module( class_module );
+ var_set( class_module, constant_name, xname, VAR_SET );
+ var_set( class_module, constant_bases, bases, VAR_SET );
- var_set( "__name__", xname, VAR_SET );
- var_set( "__bases__", bases, VAR_SET );
+ iter = list_begin( bases ), end = list_end( bases );
+ for ( ; iter != end; iter = list_next( iter ) )
+ import_base_rules( class_module, list_item( iter ) );
- exit_module( class_module );
- enter_module( outer_module );
+ return name;
+}
- for ( ; bases; bases = bases->next )
- import_base_rules( class_module, bases->string );
+static void free_class( void * xclass, void * data )
+{
+ object_free( *(OBJECT * *)xclass );
+}
- return name;
+void class_done( void )
+{
+ if( classes )
+ {
+ hashenumerate( classes, free_class, (void *)0 );
+ hashdone( classes );
+ classes = 0;
+ }
}
diff --git a/tools/build/v2/engine/class.h b/tools/build/v2/engine/class.h
index f7faeff62e..256d298b53 100644
--- a/tools/build/v2/engine/class.h
+++ b/tools/build/v2/engine/class.h
@@ -8,6 +8,7 @@
#include "lists.h"
#include "frames.h"
-char* make_class_module(LIST* xname, LIST* bases, FRAME* frame);
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame );
+void class_done( void );
#endif
diff --git a/tools/build/v2/engine/command.c b/tools/build/v2/engine/command.c
index d2ea068149..8161014c05 100644
--- a/tools/build/v2/engine/command.c
+++ b/tools/build/v2/engine/command.c
@@ -33,10 +33,11 @@
CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
{
CMD * cmd = (CMD *)BJAM_MALLOC( sizeof( CMD ) );
+ LISTITER iter = list_begin( shell ), end = list_end( shell );
/* Lift line-length limitation entirely when JAMSHELL is just "%". */
- int no_limit = ( shell && !strcmp(shell->string,"%") && !list_next(shell) );
+ int no_limit = ( iter != end && !strcmp( object_str( list_item( iter ) ), "%") && list_next( iter ) == end );
int max_line = MAXLINE;
- int allocated = -1;
+ FRAME frame[1];
cmd->rule = rule;
cmd->shell = shell;
@@ -45,27 +46,20 @@ CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
lol_init( &cmd->args );
lol_add( &cmd->args, targets );
lol_add( &cmd->args, sources );
- cmd->buf = 0;
+ string_new( cmd->buf );
- do
- {
- BJAM_FREE( cmd->buf ); /* free any buffer from previous iteration */
-
- cmd->buf = (char*)BJAM_MALLOC_ATOMIC( max_line + 1 );
-
- if ( cmd->buf == 0 )
- break;
-
- allocated = var_string( rule->actions->command, cmd->buf, max_line, &cmd->args );
-
- max_line = max_line * 2;
- }
- while ( ( allocated < 0 ) && ( max_line < INT_MAX / 2 ) );
+ frame_init( frame );
+ frame->module = rule->module;
+ lol_init( frame->args );
+ lol_add( frame->args, list_copy( targets ) );
+ lol_add( frame->args, list_copy( sources ) );
+ function_run_actions( rule->actions->command, frame, stack_global(), cmd->buf );
+ frame_free( frame );
if ( !no_limit )
{
/* Bail if the result will not fit in MAXLINE. */
- char * s = cmd->buf;
+ char * s = cmd->buf->value;
while ( *s )
{
size_t l = strcspn( s, "\n" );
@@ -95,6 +89,6 @@ void cmd_free( CMD * cmd )
{
lol_free( &cmd->args );
list_free( cmd->shell );
- BJAM_FREE( cmd->buf );
- BJAM_FREE( (char *)cmd );
+ string_free( cmd->buf );
+ BJAM_FREE( (void *)cmd );
}
diff --git a/tools/build/v2/engine/command.h b/tools/build/v2/engine/command.h
index ddd38e6897..4dad9e254c 100644
--- a/tools/build/v2/engine/command.h
+++ b/tools/build/v2/engine/command.h
@@ -36,6 +36,13 @@
* CMD - an action, ready to be formatted into a buffer and executed.
*/
+#ifndef COMMAND_SW20111118_H
+#define COMMAND_SW20111118_H
+
+#include "lists.h"
+#include "rules.h"
+#include "strings.h"
+
typedef struct _cmd CMD;
struct _cmd
@@ -45,7 +52,7 @@ struct _cmd
RULE * rule; /* rule->actions contains shell script */
LIST * shell; /* $(SHELL) value */
LOL args; /* LISTs for $(<), $(>) */
- char * buf; /* actual commands */
+ string buf[1]; /* actual commands */
};
CMD * cmd_new
@@ -59,3 +66,5 @@ CMD * cmd_new
void cmd_free( CMD * );
#define cmd_next( c ) ( ( c )->next )
+
+#endif
diff --git a/tools/build/v2/engine/compile.c b/tools/build/v2/engine/compile.c
index 2c049aae59..cb08e24c95 100644
--- a/tools/build/v2/engine/compile.c
+++ b/tools/build/v2/engine/compile.c
@@ -16,9 +16,8 @@
# include "parse.h"
# include "compile.h"
# include "variable.h"
-# include "expand.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "make.h"
# include "search.h"
# include "hdrmacro.h"
@@ -27,6 +26,7 @@
# include "strings.h"
# include "builtins.h"
# include "class.h"
+# include "constants.h"
# include <assert.h>
# include <string.h>
@@ -86,15 +86,17 @@
* 01/10/00 (seiwald) - built-ins split out to builtin.c.
*/
-static void debug_compile( int which, char *s, FRAME* frame );
-int glob( char *s, char *c );
+static void debug_compile( int which, const char * s, FRAME * frame );
+int glob( const char * s, const char * c );
/* Internal functions from builtins.c */
-void backtrace( FRAME *frame );
-void backtrace_line( FRAME *frame );
-void print_source_line( PARSE* p );
+void backtrace( FRAME * frame );
+void backtrace_line( FRAME * frame );
+void print_source_line( FRAME * frame );
struct frame * frame_before_python_call;
+static OBJECT * module_scope;
+
void frame_init( FRAME* frame )
{
frame->prev = 0;
@@ -102,7 +104,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
@@ -113,907 +116,39 @@ void frame_free( FRAME* frame )
/*
- * compile_append() - append list results of two statements
- *
- * parse->left more compile_append() by left-recursion
- * parse->right single rule
- */
-
-LIST * compile_append( PARSE * parse, FRAME * frame )
-{
- /* Append right to left. */
- return list_append(
- parse_evaluate( parse->left, frame ),
- parse_evaluate( parse->right, frame ) );
-}
-
-
-/*
- * compile_eval() - evaluate if to determine which leg to compile
- *
- * Returns:
- * list if expression true - compile 'then' clause
- * L0 if expression false - compile 'else' clause
- */
-
-static int lcmp( LIST * t, LIST * s )
-{
- int status = 0;
-
- while ( !status && ( t || s ) )
- {
- char *st = t ? t->string : "";
- char *ss = s ? s->string : "";
-
- status = strcmp( st, ss );
-
- t = t ? list_next( t ) : t;
- s = s ? list_next( s ) : s;
- }
-
- return status;
-}
-
-LIST * compile_eval( PARSE * parse, FRAME * frame )
-{
- LIST * ll;
- LIST * lr;
- LIST * s;
- LIST * t;
- int status = 0;
-
- /* Short circuit lr eval for &&, ||, and 'in'. */
-
- ll = parse_evaluate( parse->left, frame );
- lr = 0;
-
- switch ( parse->num )
- {
- case EXPR_AND:
- case EXPR_IN : if ( ll ) goto eval; break;
- case EXPR_OR : if ( !ll ) goto eval; break;
- default: eval: lr = parse_evaluate( parse->right, frame );
- }
-
- /* Now eval. */
- switch ( parse->num )
- {
- case EXPR_NOT: if ( !ll ) status = 1; break;
- case EXPR_AND: if ( ll && lr ) status = 1; break;
- case EXPR_OR : if ( ll || lr ) status = 1; break;
-
- case EXPR_IN:
- /* "a in b": make sure each of ll is equal to something in lr. */
- for ( t = ll; t; t = list_next( t ) )
- {
- for ( s = lr; s; s = list_next( s ) )
- if ( !strcmp( t->string, s->string ) )
- break;
- if ( !s ) break;
- }
- /* No more ll? Success. */
- if ( !t ) status = 1;
- break;
-
- case EXPR_EXISTS: if ( lcmp( ll, L0 ) != 0 ) status = 1; break;
- case EXPR_EQUALS: if ( lcmp( ll, lr ) == 0 ) status = 1; break;
- case EXPR_NOTEQ : if ( lcmp( ll, lr ) != 0 ) status = 1; break;
- case EXPR_LESS : if ( lcmp( ll, lr ) < 0 ) status = 1; break;
- case EXPR_LESSEQ: if ( lcmp( ll, lr ) <= 0 ) status = 1; break;
- case EXPR_MORE : if ( lcmp( ll, lr ) > 0 ) status = 1; break;
- case EXPR_MOREEQ: if ( lcmp( ll, lr ) >= 0 ) status = 1; break;
- }
-
- if ( DEBUG_IF )
- {
- debug_compile( 0, "if", frame );
- list_print( ll );
- printf( "(%d) ", status );
- list_print( lr );
- printf( "\n" );
- }
-
- /* Find something to return. */
- /* In odd circumstances (like "" = "") */
- /* we'll have to return a new string. */
-
- if ( !status ) t = 0;
- else if ( ll ) t = ll, ll = 0;
- else if ( lr ) t = lr, lr = 0;
- else t = list_new( L0, newstr( "1" ) );
-
- if ( ll ) list_free( ll );
- if ( lr ) list_free( lr );
- return t;
-}
-
-
-/*
- * compile_foreach() - compile the "for x in y" statement
- *
- * Compile_foreach() resets the given variable name to each specified
- * value, executing the commands enclosed in braces for each iteration.
- *
- * parse->string index variable
- * parse->left variable values
- * parse->right rule to compile
- */
-
-LIST * compile_foreach( PARSE * parse, FRAME * frame )
-{
- LIST * nv = parse_evaluate( parse->left, frame );
- LIST * l;
- SETTINGS * s = 0;
-
- if ( parse->num )
- {
- s = addsettings( s, VAR_SET, parse->string, L0 );
- pushsettings( s );
- }
-
- /* Call var_set to reset $(parse->string) for each val. */
-
- for ( l = nv; l; l = list_next( l ) )
- {
- LIST * val = list_new( L0, copystr( l->string ) );
- var_set( parse->string, val, VAR_SET );
- list_free( parse_evaluate( parse->right, frame ) );
- }
-
- if ( parse->num )
- {
- popsettings( s );
- freesettings( s );
- }
-
- list_free( nv );
-
- return L0;
-}
-
-/*
- * compile_if() - compile 'if' rule
- *
- * parse->left condition tree
- * parse->right then tree
- * parse->third else tree
- */
-
-LIST * compile_if( PARSE * p, FRAME * frame )
-{
- LIST * l = parse_evaluate( p->left, frame );
- if ( l )
- {
- list_free( l );
- return parse_evaluate( p->right, frame );
- }
- return parse_evaluate( p->third, frame );
-}
-
-
-LIST * compile_while( PARSE * p, FRAME * frame )
-{
- LIST * r = 0;
- LIST * l;
- while ( ( l = parse_evaluate( p->left, frame ) ) )
- {
- list_free( l );
- if ( r ) list_free( r );
- r = parse_evaluate( p->right, frame );
- }
- return r;
-}
-
-
-/*
- * compile_include() - support for 'include' - call include() on file
- *
- * parse->left list of files to include (can only do 1)
- */
-
-LIST * compile_include( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "include", frame);
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
-
- /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
- * prevents an included file from being treated as part of the body of a
- * rule. I did not see any reason to do that, so I lifted the
- * restriction.
- */
-
- /* Bind the include file under the influence of */
- /* "on-target" variables. Though they are targets, */
- /* include files are not built with make(). */
-
- pushsettings( t->settings );
- /* We don't expect that file to be included is generated by some
- action. Therefore, pass 0 as third argument.
- If the name resolves to directory, let it error out. */
- t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
-
- parse_file( t->boundname, frame );
- }
-
- list_free( nt );
-
- return L0;
-}
-
-static LIST* evaluate_in_module ( char* module_name, PARSE * p, FRAME* frame)
-{
- LIST* result;
-
- module_t* outer_module = frame->module;
- frame->module = module_name ? bindmodule( module_name ) : root_module();
-
- if ( outer_module != frame->module )
- {
- exit_module( outer_module );
- enter_module( frame->module );
- }
-
- result = parse_evaluate( p, frame );
-
- if ( outer_module != frame->module )
- {
- exit_module( frame->module );
- enter_module( outer_module );
- frame->module = outer_module;
- }
-
- return result;
-}
-
-
-LIST * compile_module( PARSE * p, FRAME * frame )
-{
- /* Here we are entering a module declaration block. */
- LIST * module_name = parse_evaluate( p->left, frame );
- LIST * result = evaluate_in_module( module_name ? module_name->string : 0,
- p->right, frame );
- list_free( module_name );
- return result;
-}
-
-
-LIST * compile_class( PARSE * p, FRAME * frame )
-{
- /** Todo: check for empty class name.
- Check for class redeclaration. */
-
- char * class_module = 0;
-
- LIST * name = parse_evaluate( p->left->right, frame );
- LIST * bases = 0;
-
- if ( p->left->left )
- bases = parse_evaluate( p->left->left->right, frame );
-
- class_module = make_class_module( name, bases, frame );
- evaluate_in_module( class_module, p->right, frame );
-
- return L0;
-}
-
-
-/*
- * compile_list() - expand and return a list.
- *
- * parse->string - character string to expand.
- */
-
-LIST * compile_list( PARSE * parse, FRAME * frame )
-{
- /* s is a copyable string */
- char * s = parse->string;
- return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
-}
-
-
-/*
- * compile_local() - declare (and set) local variables.
- *
- * parse->left list of variables
- * parse->right list of values
- * parse->third rules to execute
- */
-
-LIST * compile_local( PARSE * parse, FRAME * frame )
-{
- LIST * l;
- SETTINGS * s = 0;
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * result;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "local", frame );
- list_print( nt );
- printf( " = " );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Initial value is ns. */
- for ( l = nt; l; l = list_next( l ) )
- s = addsettings( s, VAR_SET, l->string, list_copy( (LIST *)0, ns ) );
-
- list_free( ns );
- list_free( nt );
-
- /* Note that callees of the current context get this "local" variable,
- * making it not so much local as layered.
- */
-
- pushsettings( s );
- result = parse_evaluate( parse->third, frame );
- popsettings( s );
-
- freesettings( s );
-
- return result;
-}
-
-
-/*
- * compile_null() - do nothing -- a stub for parsing.
- */
-
-LIST * compile_null( PARSE * parse, FRAME * frame )
-{
- return L0;
-}
-
-
-/*
- * compile_on() - run rule under influence of on-target variables
- *
- * parse->left list of files to include (can only do 1).
- * parse->right rule to run.
- *
- * EXPERIMENTAL!
- */
-
-LIST * compile_on( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "on", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
- pushsettings( t->settings );
- result = parse_evaluate( parse->right, frame );
- popsettings( t->settings );
- }
-
- list_free( nt );
-
- return result;
-}
-
-
-/*
- * compile_rule() - compile a single user defined rule.
- *
- * parse->string name of user defined rule.
- * parse->left parameters (list of lists) to rule, recursing left.
- *
- * Wrapped around evaluate_rule() so that headers() can share it.
- */
-
-LIST * compile_rule( PARSE * parse, FRAME * frame )
-{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
-
- /* Build up the list of arg lists. */
- frame_init( inner );
- inner->prev = frame;
- inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
- inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
- inner->procedure = parse;
- /* Special-case LOL of length 1 where the first list is totally empty.
- This is created when calling functions with no parameters, due to
- the way jam grammar is written. This is OK when one jam function
- calls another, but really not good when Jam function calls Python. */
- if ( parse->left->left == NULL && parse->left->right->func == compile_null)
- ;
- else
- for ( p = parse->left; p; p = p->left )
- lol_add( inner->args, parse_evaluate( p->right, frame ) );
-
- /* And invoke the rule. */
- result = evaluate_rule( parse->string, inner );
- frame_free( inner );
- return result;
-}
-
-
-static void argument_error( char * message, RULE * rule, FRAME * frame, LIST* arg )
-{
- LOL * actual = frame->args;
- assert( frame->procedure != 0 );
- backtrace_line( frame->prev );
- printf( "*** argument error\n* rule %s ( ", frame->rulename );
- lol_print( rule->arguments->data );
- printf( " )\n* called with: ( " );
- lol_print( actual );
- printf( " )\n* %s %s\n", message, arg ? arg->string : "" );
- print_source_line( rule->procedure );
- printf( "see definition of rule '%s' being called\n", rule->name );
- backtrace( frame->prev );
- exit( 1 );
-}
-
-
-/* Define delimiters for type check elements in argument lists (and return type
- * specifications, eventually).
- */
-# define TYPE_OPEN_DELIM '['
-# define TYPE_CLOSE_DELIM ']'
-
-/*
- * is_type_name() - true iff the given string represents a type check
- * specification.
- */
-
-static int is_type_name( char * s )
-{
- return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
- ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
-}
-
-
-/*
- * arg_modifier - if the next element of formal is a single character, return
- * that; return 0 otherwise. Used to extract "*+?" modifiers * from argument
- * lists.
- */
-
-static char arg_modifier( LIST * formal )
-{
- if ( formal->next )
- {
- char * next = formal->next->string;
- if ( next && ( next[ 0 ] != 0 ) && ( next[ 1 ] == 0 ) )
- return next[ 0 ];
- }
- return 0;
-}
-
-
-/*
- * type_check() - checks that each element of values satisfies the requirements
- * of type_name.
- *
- * caller - the frame of the rule calling the rule whose arguments are
- * being checked
- *
- * called - the rule being called
- *
- * arg_name - a list element containing the name of the argument being
- * checked
- */
-
-static void type_check
-(
- char * type_name,
- LIST * values,
- FRAME * caller,
- RULE * called,
- LIST * arg_name
-)
-{
- static module_t * typecheck = 0;
-
- /* If nothing to check, bail now. */
- if ( !values || !type_name )
- return;
-
- if ( !typecheck )
- typecheck = bindmodule( ".typecheck" );
-
- /* If the checking rule can not be found, also bail. */
- {
- RULE checker_, *checker = &checker_;
-
- checker->name = type_name;
- if ( !typecheck->rules || !hashcheck( typecheck->rules, (HASHDATA * *)&checker ) )
- return;
- }
-
- exit_module( caller->module );
-
- while ( values != 0 )
- {
- LIST *error;
- FRAME frame[1];
- frame_init( frame );
- frame->module = typecheck;
- frame->prev = caller;
- frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
-
- enter_module( typecheck );
- /* Prepare the argument list */
- lol_add( frame->args, list_new( L0, values->string ) );
- error = evaluate_rule( type_name, frame );
-
- exit_module( typecheck );
-
- if ( error )
- argument_error( error->string, called, caller, arg_name );
-
- frame_free( frame );
- values = values->next;
- }
-
- enter_module( caller->module );
-}
-
-/*
- * collect_arguments() - local argument checking and collection
- */
-static SETTINGS *
-collect_arguments( RULE* rule, FRAME* frame )
-{
- SETTINGS *locals = 0;
-
- LOL * all_actual = frame->args;
- LOL * all_formal = rule->arguments ? rule->arguments->data : 0;
- if ( all_formal ) /* Nothing to set; nothing to check */
- {
- int max = all_formal->count > all_actual->count
- ? all_formal->count
- : all_actual->count;
-
- int n;
- for ( n = 0; n < max ; ++n )
- {
- LIST *actual = lol_get( all_actual, n );
- char *type_name = 0;
-
- LIST *formal;
- for ( formal = lol_get( all_formal, n ); formal; formal = formal->next )
- {
- char* name = formal->string;
-
- if ( is_type_name(name) )
- {
- if ( type_name )
- argument_error( "missing argument name before type name:", rule, frame, formal );
-
- if ( !formal->next )
- argument_error( "missing argument name after type name:", rule, frame, formal );
-
- type_name = formal->string;
- }
- else
- {
- LIST* value = 0;
- char modifier;
- LIST* arg_name = formal; /* hold the argument name for type checking */
- int multiple = 0;
-
- /* Stop now if a variable number of arguments are specified */
- if ( name[0] == '*' && name[1] == 0 )
- return locals;
-
- modifier = arg_modifier( formal );
-
- if ( !actual && modifier != '?' && modifier != '*' )
- argument_error( "missing argument", rule, frame, formal );
-
- switch ( modifier )
- {
- case '+':
- case '*':
- value = list_copy( 0, actual );
- multiple = 1;
- actual = 0;
- /* skip an extra element for the modifier */
- formal = formal->next;
- break;
- case '?':
- /* skip an extra element for the modifier */
- formal = formal->next;
- /* fall through */
- default:
- if ( actual ) /* in case actual is missing */
- {
- value = list_new( 0, actual->string );
- actual = actual->next;
- }
- }
-
- locals = addsettings(locals, VAR_SET, name, value);
- locals->multiple = multiple;
- type_check( type_name, value, frame, rule, arg_name );
- type_name = 0;
- }
- }
-
- if ( actual )
- {
- argument_error( "extra argument", rule, frame, actual );
- }
- }
- }
- return locals;
-}
-
-RULE *
-enter_rule( char *rulename, module_t *target_module );
-
-#ifdef HAVE_PYTHON
-
-static int python_instance_number = 0;
-
-
-/* Given a Python object, return a string to use in Jam
- code instead of said object.
- If the object is string, use the string value
- If the object implemenets __jam_repr__ method, use that.
- Otherwise return 0.
-
- The result value is newstr-ed. */
-char *python_to_string(PyObject* value)
-{
- if (PyString_Check(value))
- {
- return newstr(PyString_AsString(value));
- }
- else
- {
- /* See if this is an instance that defines special __jam_repr__
- method. */
- if (PyInstance_Check(value)
- && PyObject_HasAttrString(value, "__jam_repr__"))
- {
- PyObject* repr = PyObject_GetAttrString(value, "__jam_repr__");
- if (repr)
- {
- PyObject* arguments2 = PyTuple_New(0);
- PyObject* value2 = PyObject_Call(repr, arguments2, 0);
- Py_DECREF(repr);
- Py_DECREF(arguments2);
- if (PyString_Check(value2))
- {
- return newstr(PyString_AsString(value2));
- }
- Py_DECREF(value2);
- }
- }
- return 0;
- }
-}
-
-static LIST*
-call_python_function(RULE* r, FRAME* frame)
-{
- LIST * result = 0;
- PyObject * arguments = 0;
- PyObject * kw = NULL;
- int i ;
- PyObject * py_result;
-
- if (r->arguments)
- {
- SETTINGS * args;
-
- arguments = PyTuple_New(0);
- kw = PyDict_New();
-
- for (args = collect_arguments(r, frame); args; args = args->next)
- {
- PyObject *key = PyString_FromString(args->symbol);
- PyObject *value = 0;
- if (args->multiple)
- value = list_to_python(args->value);
- else {
- if (args->value)
- value = PyString_FromString(args->value->string);
- }
-
- if (value)
- PyDict_SetItem(kw, key, value);
- Py_DECREF(key);
- Py_XDECREF(value);
- }
- }
- else
- {
- arguments = PyTuple_New( frame->args->count );
- for ( i = 0; i < frame->args->count; ++i )
- {
- PyObject * arg = PyList_New(0);
- LIST* l = lol_get( frame->args, i);
-
- for ( ; l; l = l->next )
- {
- PyObject * v = PyString_FromString(l->string);
- PyList_Append( arg, v );
- Py_DECREF(v);
- }
- /* Steals reference to 'arg' */
- PyTuple_SetItem( arguments, i, arg );
- }
- }
-
- frame_before_python_call = frame;
- py_result = PyObject_Call( r->python_function, arguments, kw );
- Py_DECREF(arguments);
- Py_XDECREF(kw);
- if ( py_result != NULL )
- {
- if ( PyList_Check( py_result ) )
- {
- int size = PyList_Size( py_result );
- int i;
- for ( i = 0; i < size; ++i )
- {
- PyObject * item = PyList_GetItem( py_result, i );
- char *s = python_to_string (item);
- if (!s) {
- fprintf( stderr, "Non-string object returned by Python call.\n" );
- } else {
- result = list_new (result, s);
- }
- }
- }
- else if ( py_result == Py_None )
- {
- result = L0;
- }
- else
- {
- char *s = python_to_string(py_result);
- if (s)
- result = list_new(0, s);
- else
- /* We have tried all we could. Return empty list. There are
- cases, e.g. feature.feature function that should return
- value for the benefit of Python code and which also can be
- called by Jam code, where no sensible value can be
- returned. We cannot even emit a warning, since there will
- be a pile of them. */
- result = L0;
- }
-
- Py_DECREF( py_result );
- }
- else
- {
- PyErr_Print();
- fprintf(stderr,"Call failed\n");
- }
-
- return result;
-}
-
-
-module_t * python_module()
-{
- static module_t * python = 0;
- if ( !python )
- python = bindmodule("__python__");
- return python;
-}
-
-#endif
-
-
-/*
* evaluate_rule() - execute a rule invocation.
*/
LIST *
evaluate_rule(
- char * rulename,
- FRAME * frame )
+ OBJECT * rulename,
+ FRAME * frame )
{
LIST * result = L0;
RULE * rule;
profile_frame prof[1];
module_t * prev_module = frame->module;
- LIST * l;
- {
- LOL arg_context_, * arg_context = &arg_context_;
- if ( !frame->prev )
- lol_init(arg_context);
- else
- arg_context = frame->prev->args;
- l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 );
- }
-
- if ( !l )
- {
- backtrace_line( frame->prev );
- printf( "warning: rulename %s expands to empty string\n", rulename );
- backtrace( frame->prev );
- return result;
- }
-
- rulename = l->string;
- rule = bindrule( l->string, frame->module );
-
-#ifdef HAVE_PYTHON
- if ( rule->python_function )
- {
- /* The below messing with modules is due to the way modules are
- * implemented in Jam. Suppose we are in module M1 now. The global
- * variable map actually holds 'M1' variables, and M1->variables hold
- * global variables.
- *
- * If we call Python right away, Python calls back Jam and then Jam
- * does 'module M1 { }' then Jam will try to swap the current global
- * variables with M1->variables. The result will be that global
- * variables map will hold global variables, and any variable settings
- * we do will go to the global module, not M1.
- *
- * By restoring basic state, where the global variable map holds global
- * variable, we make sure any future 'module M1' entry will work OK.
- */
-
- LIST * result;
- module_t * m = python_module();
-
- frame->module = m;
-
- exit_module( prev_module );
- enter_module( m );
-
- result = call_python_function( rule, frame );
-
- exit_module( m );
- enter_module ( prev_module );
-
- return result;
- }
-#endif
-
- /* Drop the rule name. */
- l = list_pop_front( l );
-
- /* Tack the rest of the expansion onto the front of the first argument. */
- frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );
+ rule = bindrule( rulename, frame->module );
if ( DEBUG_COMPILE )
{
/* Try hard to indicate in which module the rule is going to execute. */
if ( rule->module != frame->module
- && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) )
+ && rule->procedure != 0 && !object_equal( rulename, function_rulename( rule->procedure ) ) )
{
char buf[256] = "";
- strncat( buf, rule->module->name, sizeof( buf ) - 1 );
- strncat( buf, rule->name, sizeof( buf ) - 1 );
+ if ( rule->module->name )
+ {
+ strncat( buf, object_str( rule->module->name ), sizeof( buf ) - 1 );
+ strncat( buf, ".", sizeof( buf ) - 1 );
+ }
+ strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 );
debug_compile( 1, buf, frame );
}
else
{
- debug_compile( 1, rulename, frame );
+ debug_compile( 1, object_str( rulename ), frame );
}
lol_print( frame->args );
@@ -1024,26 +159,29 @@ evaluate_rule(
{
/* Propagate current module to nested rule invocations. */
frame->module = rule->module;
-
- /* Swap variables. */
- exit_module( prev_module );
- enter_module( rule->module );
}
/* Record current rule name in frame. */
if ( rule->procedure )
{
- frame->rulename = rulename;
+ frame->rulename = object_str( rulename );
/* And enter record profile info. */
if ( DEBUG_PROFILE )
- profile_enter( rule->procedure->rulename, prof );
+ profile_enter( function_rulename( rule->procedure ), prof );
}
/* Check traditional targets $(<) and sources $(>). */
if ( !rule->actions && !rule->procedure )
{
backtrace_line( frame->prev );
- printf( "rule %s unknown in module %s\n", rule->name, frame->module->name );
+ if ( frame->module->name )
+ {
+ printf( "rule %s unknown in module %s\n", object_str( rule->name ), object_str( frame->module->name ) );
+ }
+ else
+ {
+ printf( "rule %s unknown in module \n", object_str( rule->name ) );
+ }
backtrace( frame->prev );
exit( 1 );
}
@@ -1063,6 +201,7 @@ evaluate_rule(
action->rule = rule;
action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );
+ action->refs = 1;
/* If we have a group of targets all being built using the same action
* then we must not allow any of them to be used as sources unless they
@@ -1109,30 +248,21 @@ evaluate_rule(
/* Append this action to the actions of each target. */
for ( t = action->targets; t; t = t->next )
t->target->actions = actionlist( t->target->actions, action );
+
+ action_free( action );
}
/* Now recursively compile any parse tree associated with this rule.
- * parse_refer()/parse_free() call pair added to ensure rule not freed
+ * function_refer()/function_free() call pair added to ensure rule not freed
* during use.
*/
if ( rule->procedure )
{
- SETTINGS * local_args = collect_arguments( rule, frame );
- PARSE * parse = rule->procedure;
- parse_refer( parse );
-
- pushsettings( local_args );
- result = parse_evaluate( parse, frame );
- popsettings( local_args );
- freesettings( local_args );
+ FUNCTION * function = rule->procedure;
- parse_free( parse );
- }
-
- if ( frame->module != prev_module )
- {
- exit_module( frame->module );
- enter_module( prev_module );
+ function_refer( function );
+ result = function_run( function, frame, stack_global() );
+ function_free( function );
}
if ( DEBUG_PROFILE && rule->procedure )
@@ -1154,7 +284,7 @@ evaluate_rule(
* which might be implemented in Jam.
*/
-LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
+LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... )
{
va_list va;
LIST * result;
@@ -1165,7 +295,6 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
inner->prev_user = caller_frame->module->user_module ?
caller_frame : caller_frame->prev_user;
inner->module = caller_frame->module;
- inner->procedure = 0;
va_start( va, caller_frame );
for ( ; ; )
@@ -1185,218 +314,12 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
}
-/*
- * compile_rules() - compile a chain of rules
- *
- * parse->left single rule
- * parse->right more compile_rules() by right-recursion
- */
-
-LIST * compile_rules( PARSE * parse, FRAME * frame )
-{
- /* Ignore result from first statement; return the 2nd. */
- /* Optimize recursion on the right by looping. */
- do list_free( parse_evaluate( parse->left, frame ) );
- while ( ( parse = parse->right )->func == compile_rules );
- return parse_evaluate( parse, frame );
-}
-
-
-/*
- * assign_var_mode() - convert ASSIGN_XXX compilation flag into corresponding
- * VAR_XXX variable set flag.
- */
-
-static int assign_var_mode( int parsenum, char const * * tracetext )
-{
- char const * trace;
- int setflag;
- switch ( parsenum )
- {
- case ASSIGN_SET : setflag = VAR_SET ; trace = "=" ; break;
- case ASSIGN_APPEND : setflag = VAR_APPEND ; trace = "+="; break;
- case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
- default: setflag = VAR_SET ; trace = "" ; break;
- }
- if ( tracetext )
- *tracetext = trace ;
- return setflag;
-}
-
-/*
- * compile_set() - compile the "set variable" statement
- *
- * parse->left variable names
- * parse->right variable values
- * parse->num ASSIGN_SET/APPEND/DEFAULT
- */
-
-LIST * compile_set( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * l;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call var_set to set variable. var_set keeps ns, so need to copy it. */
- for ( l = nt; l; l = list_next( l ) )
- var_set( l->string, list_copy( L0, ns ), setflag );
- list_free( nt );
- return ns;
-}
-
-
-/*
- * compile_setcomp() - support for `rule` - save parse tree.
- *
- * parse->string rule name
- * parse->left rules for rule
- * parse->right optional list-of-lists describing arguments
- */
-
-LIST * compile_setcomp( PARSE * parse, FRAME * frame )
-{
- argument_list * arg_list = 0;
-
- /* Create new LOL describing argument requirements if supplied. */
- if ( parse->right )
- {
- PARSE * p;
- arg_list = args_new();
- for ( p = parse->right; p; p = p->left )
- lol_add( arg_list->data, parse_evaluate( p->right, frame ) );
- }
-
- new_rule_body( frame->module, parse->string, arg_list, parse->left, !parse->num );
- return L0;
-}
-
-
-/*
- * compile_setexec() - support for `actions` - save execution string.
- *
- * parse->string rule name
- * parse->string1 OS command string
- * parse->num flags
- * parse->left `bind` variables
- *
- * Note that the parse flags (as defined in compile.h) are transferred directly
- * to the rule flags (as defined in rules.h).
- */
-
-LIST * compile_setexec( PARSE * parse, FRAME * frame )
-{
- LIST * bindlist = parse_evaluate( parse->left, frame );
- new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
- return L0;
-}
-
-
-/*
- * compile_settings() - compile the "on =" (set variable on exec) statement.
- *
- * parse->left variable names
- * parse->right target name
- * parse->third variable value
- * parse->num ASSIGN_SET/APPEND
- */
-
-LIST * compile_settings( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->third, frame );
- LIST * targets = parse_evaluate( parse->right, frame );
- LIST * ts;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " on " );
- list_print( targets );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call addsettings() to save variable setting. addsettings() keeps ns, so
- * need to copy it. Pass append flag to addsettings().
- */
- for ( ts = targets; ts; ts = list_next( ts ) )
- {
- TARGET * t = bindtarget( ts->string );
- LIST * l;
-
- for ( l = nt; l; l = list_next( l ) )
- t->settings = addsettings( t->settings, setflag, l->string,
- list_copy( (LIST *)0, ns ) );
- }
-
- list_free( nt );
- list_free( targets );
- return ns;
-}
-
-
-/*
- * compile_switch() - compile 'switch' rule.
- *
- * parse->left switch value (only 1st used)
- * parse->right cases
- *
- * cases->left 1st case
- * cases->right next cases
- *
- * case->string argument to match
- * case->left parse tree to execute
- */
-
-LIST * compile_switch( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "switch", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- /* Step through cases. */
- for ( parse = parse->right; parse; parse = parse->right )
- {
- if ( !glob( parse->left->string, nt ? nt->string : "" ) )
- {
- /* Get & exec parse tree for this case. */
- parse = parse->left->left;
- result = parse_evaluate( parse, frame );
- break;
- }
- }
-
- list_free( nt );
- return result;
-}
-
/*
* debug_compile() - printf with indent to show rule expansion.
*/
-static void debug_compile( int which, char * s, FRAME * frame )
+static void debug_compile( int which, const char * s, FRAME * frame )
{
static int level = 0;
static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
@@ -1405,7 +328,7 @@ static void debug_compile( int which, char * s, FRAME * frame )
{
int i;
- print_source_line( frame->procedure );
+ print_source_line( frame );
i = ( level + 1 ) * 2;
while ( i > 35 )
diff --git a/tools/build/v2/engine/compile.h b/tools/build/v2/engine/compile.h
index 7d5191f0e1..1c002d90fa 100644
--- a/tools/build/v2/engine/compile.h
+++ b/tools/build/v2/engine/compile.h
@@ -16,6 +16,7 @@
# include "frames.h"
# include "parse.h"
# include "regexp.h"
+# include "object.h"
/*
* compile.h - compile parsed jam statements
@@ -23,30 +24,10 @@
void compile_builtins();
-LIST *compile_append( PARSE *parse, FRAME *frame );
-LIST *compile_foreach( PARSE *parse, FRAME *frame );
-LIST *compile_if( PARSE *parse, FRAME *frame );
-LIST *compile_eval( PARSE *parse, FRAME *args );
-LIST *compile_include( PARSE *parse, FRAME *frame );
-LIST *compile_list( PARSE *parse, FRAME *frame );
-LIST *compile_local( PARSE *parse, FRAME *frame );
-LIST *compile_module( PARSE *parse, FRAME *frame );
-LIST *compile_class( PARSE *parse, FRAME *frame );
-LIST *compile_null( PARSE *parse, FRAME *frame );
-LIST *compile_on( PARSE *parse, FRAME *frame );
-LIST *compile_rule( PARSE *parse, FRAME *frame );
-LIST *compile_rules( PARSE *parse, FRAME *frame );
-LIST *compile_set( PARSE *parse, FRAME *frame );
-LIST *compile_setcomp( PARSE *parse, FRAME *frame );
-LIST *compile_setexec( PARSE *parse, FRAME *frame );
-LIST *compile_settings( PARSE *parse, FRAME *frame );
-LIST *compile_switch( PARSE *parse, FRAME *frame );
-LIST *compile_while( PARSE *parse, FRAME *frame );
-
-LIST *evaluate_rule( char *rulename, FRAME *frame );
-LIST *call_rule( char *rulename, FRAME* caller_frame, ...);
-
-regexp* regex_compile( const char* pattern );
+LIST *evaluate_rule( OBJECT * rulename, FRAME * frame );
+LIST *call_rule( OBJECT * rulename, FRAME * caller_frame, ...);
+
+regexp* regex_compile( OBJECT * pattern );
/* Flags for compile_set(), etc */
diff --git a/tools/build/v2/engine/constants.c b/tools/build/v2/engine/constants.c
new file mode 100644
index 0000000000..3ad534ed75
--- /dev/null
+++ b/tools/build/v2/engine/constants.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "constants.h"
+# include "object.h"
+
+/*
+ * constants.c - constant objects
+ *
+ * External functions:
+ *
+ * constants_init() - initialize constants
+ * constants_done() - free constants
+ *
+ */
+
+void constants_init( void )
+{
+ constant_empty = object_new( "" );
+ constant_dot = object_new( "." );
+ constant_percent = object_new( "%" );
+ constant_plus = object_new( "+" );
+ constant_star = object_new( "*" );
+ constant_question_mark = object_new( "?" );
+ constant_ok = object_new( "ok" );
+ constant_true = object_new( "true" );
+ constant_name = object_new( "__name__" );
+ constant_bases = object_new( "__bases__" );
+ constant_typecheck = object_new( ".typecheck" );
+ constant_builtin = object_new( "(builtin)" );
+ constant_HCACHEFILE = object_new( "HCACHEFILE" );
+ constant_HCACHEMAXAGE = object_new( "HCACHEMAXAGE" );
+ constant_HDRSCAN = object_new( "HDRSCAN" );
+ constant_HDRRULE = object_new( "HDRRULE" );
+ constant_BINDRULE = object_new( "BINDRULE" );
+ constant_LOCATE = object_new( "LOCATE" );
+ constant_SEARCH = object_new( "SEARCH" );
+ constant_JAM_SEMAPHORE = object_new( "JAM_SEMAPHORE" );
+ constant_TIMING_RULE = object_new( "__TIMING_RULE__" );
+ constant_ACTION_RULE = object_new( "__ACTION_RULE__" );
+ constant_JAMSHELL = object_new( "JAMSHELL" );
+ constant_TMPDIR = object_new( "TMPDIR" );
+ constant_TMPNAME = object_new( "TMPNAME" );
+ constant_TMPFILE = object_new( "TMPFILE" );
+ constant_STDOUT = object_new( "STDOUT" );
+ constant_STDERR = object_new( "STDERR" );
+ constant_JAMDATE = object_new( "JAMDATE" );
+ constant_JAM_VERSION = object_new( "JAM_VERSION" );
+ constant_JAMUNAME = object_new( "JAMUNAME" );
+ constant_ENVIRON = object_new( ".ENVIRON" );
+ constant_ARGV = object_new( "ARGV" );
+ constant_all = object_new( "all" );
+ constant_PARALLELISM = object_new( "PARALLELISM" );
+ constant_KEEP_GOING = object_new( "KEEP_GOING" );
+ constant_other = object_new( "[OTHER]" );
+ constant_total = object_new( "[TOTAL]" );
+ constant_FILE_DIRSCAN = object_new( "FILE_DIRSCAN" );
+ constant_MAIN = object_new( "MAIN" );
+ constant_MAIN_MAKE = object_new( "MAIN_MAKE" );
+ constant_MAKE_MAKE0 = object_new( "MAKE_MAKE0" );
+ constant_MAKE_MAKE1 = object_new( "MAKE_MAKE1" );
+ constant_MAKE_MAKE0SORT = object_new( "MAKE_MAKE0SORT" );
+ constant_BINDMODULE = object_new( "BINDMODULE" );
+ constant_IMPORT_MODULE = object_new( "IMPORT_MODULE" );
+ constant_BUILTIN_GLOB_BACK = object_new( "BUILTIN_GLOB_BACK" );
+ constant_timestamp = object_new( "timestamp" );
+ constant_python = object_new("__python__");
+ constant_python_interface = object_new( "python_interface" );
+ constant_extra_pythonpath = object_new( "EXTRA_PYTHONPATH" );
+ constant_MAIN_PYTHON = object_new( "MAIN_PYTHON" );
+}
+
+void constants_done( void )
+{
+ object_free( constant_empty );
+ object_free( constant_dot );
+ object_free( constant_percent );
+ object_free( constant_plus );
+ object_free( constant_star );
+ object_free( constant_question_mark );
+ object_free( constant_ok );
+ object_free( constant_true );
+ object_free( constant_name );
+ object_free( constant_bases );
+ object_free( constant_typecheck );
+ object_free( constant_builtin );
+ object_free( constant_HCACHEFILE );
+ object_free( constant_HCACHEMAXAGE );
+ object_free( constant_HDRSCAN );
+ object_free( constant_HDRRULE );
+ object_free( constant_BINDRULE );
+ object_free( constant_LOCATE );
+ object_free( constant_SEARCH );
+ object_free( constant_JAM_SEMAPHORE );
+ object_free( constant_TIMING_RULE );
+ object_free( constant_ACTION_RULE );
+ object_free( constant_JAMSHELL );
+ object_free( constant_TMPDIR );
+ object_free( constant_TMPNAME );
+ object_free( constant_TMPFILE );
+ object_free( constant_STDOUT );
+ object_free( constant_STDERR );
+ object_free( constant_JAMDATE );
+ object_free( constant_JAM_VERSION );
+ object_free( constant_JAMUNAME );
+ object_free( constant_ENVIRON );
+ object_free( constant_ARGV );
+ object_free( constant_all );
+ object_free( constant_PARALLELISM );
+ object_free( constant_KEEP_GOING );
+ object_free( constant_other );
+ object_free( constant_total );
+ object_free( constant_FILE_DIRSCAN );
+ object_free( constant_MAIN );
+ object_free( constant_MAIN_MAKE );
+ object_free( constant_MAKE_MAKE0 );
+ object_free( constant_MAKE_MAKE1 );
+ object_free( constant_MAKE_MAKE0SORT );
+ object_free( constant_BINDMODULE );
+ object_free( constant_IMPORT_MODULE );
+ object_free( constant_BUILTIN_GLOB_BACK );
+ object_free( constant_timestamp );
+ object_free( constant_python );
+ object_free( constant_python_interface );
+ object_free( constant_extra_pythonpath );
+ object_free( constant_MAIN_PYTHON );
+}
+
+OBJECT * constant_empty;
+OBJECT * constant_dot;
+OBJECT * constant_percent;
+OBJECT * constant_plus;
+OBJECT * constant_star;
+OBJECT * constant_question_mark;
+OBJECT * constant_ok;
+OBJECT * constant_true;
+OBJECT * constant_name;
+OBJECT * constant_bases;
+OBJECT * constant_typecheck;
+OBJECT * constant_builtin;
+OBJECT * constant_HCACHEFILE;
+OBJECT * constant_HCACHEMAXAGE;
+OBJECT * constant_HDRSCAN;
+OBJECT * constant_HDRRULE;
+OBJECT * constant_BINDRULE;
+OBJECT * constant_LOCATE;
+OBJECT * constant_SEARCH;
+OBJECT * constant_JAM_SEMAPHORE;
+OBJECT * constant_TIMING_RULE;
+OBJECT * constant_ACTION_RULE;
+OBJECT * constant_JAMSHELL;
+OBJECT * constant_TMPDIR;
+OBJECT * constant_TMPNAME;
+OBJECT * constant_TMPFILE;
+OBJECT * constant_STDOUT;
+OBJECT * constant_STDERR;
+OBJECT * constant_JAMDATE;
+OBJECT * constant_JAM_VERSION;
+OBJECT * constant_JAMUNAME;
+OBJECT * constant_ENVIRON;
+OBJECT * constant_ARGV;
+OBJECT * constant_all;
+OBJECT * constant_PARALLELISM;
+OBJECT * constant_KEEP_GOING;
+OBJECT * constant_other;
+OBJECT * constant_total;
+OBJECT * constant_FILE_DIRSCAN;
+OBJECT * constant_MAIN;
+OBJECT * constant_MAIN_MAKE;
+OBJECT * constant_MAKE_MAKE0;
+OBJECT * constant_MAKE_MAKE1;
+OBJECT * constant_MAKE_MAKE0SORT;
+OBJECT * constant_BINDMODULE;
+OBJECT * constant_IMPORT_MODULE;
+OBJECT * constant_BUILTIN_GLOB_BACK;
+OBJECT * constant_timestamp;
+OBJECT * constant_python;
+OBJECT * constant_python_interface;
+OBJECT * constant_extra_pythonpath;
+OBJECT * constant_MAIN_PYTHON;
diff --git a/tools/build/v2/engine/constants.h b/tools/build/v2/engine/constants.h
new file mode 100644
index 0000000000..2ec27e800f
--- /dev/null
+++ b/tools/build/v2/engine/constants.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * constants.h - constant objects
+ */
+
+#ifndef BOOST_JAM_CONSTANTS_H
+#define BOOST_JAM_CONSTANTS_H
+
+#include "object.h"
+
+void constants_init( void );
+void constants_done( void );
+
+extern OBJECT * constant_empty; /* "" */
+extern OBJECT * constant_dot; /* "." */
+extern OBJECT * constant_percent; /* "%" */
+extern OBJECT * constant_plus; /* "+" */
+extern OBJECT * constant_star; /* "*" */
+extern OBJECT * constant_question_mark; /* "?" */
+extern OBJECT * constant_ok; /* "ok" */
+extern OBJECT * constant_true; /* "true" */
+extern OBJECT * constant_name; /* "__name__" */
+extern OBJECT * constant_bases; /* "__bases__" */
+extern OBJECT * constant_typecheck; /* ".typecheck" */
+extern OBJECT * constant_builtin; /* "(builtin)" */
+extern OBJECT * constant_HCACHEFILE; /* "HCACHEFILE" */
+extern OBJECT * constant_HCACHEMAXAGE; /* "HCACHEMAXAGE" */
+extern OBJECT * constant_HDRSCAN; /* "HDRSCAN" */
+extern OBJECT * constant_HDRRULE; /* "HDRRULE" */
+extern OBJECT * constant_BINDRULE; /* "BINDRULE" */
+extern OBJECT * constant_LOCATE; /* "LOCATE" */
+extern OBJECT * constant_SEARCH; /* "SEARCH" */
+extern OBJECT * constant_JAM_SEMAPHORE; /* "JAM_SEMAPHORE" */
+extern OBJECT * constant_TIMING_RULE; /* "__TIMING_RULE__" */
+extern OBJECT * constant_ACTION_RULE; /* "__ACTION_RULE__" */
+extern OBJECT * constant_JAMSHELL; /* "JAMSHELL" */
+extern OBJECT * constant_TMPDIR; /* "TMPDIR" */
+extern OBJECT * constant_TMPNAME; /* "TMPNAME" */
+extern OBJECT * constant_TMPFILE; /* "TMPFILE" */
+extern OBJECT * constant_STDOUT; /* "STDOUT" */
+extern OBJECT * constant_STDERR; /* "STDERR" */
+extern OBJECT * constant_JAMDATE; /* "JAMDATE" */
+extern OBJECT * constant_JAM_VERSION; /* "JAM_VERSION" */
+extern OBJECT * constant_JAMUNAME; /* "JAMUNAME" */
+extern OBJECT * constant_ENVIRON; /* ".ENVIRON" */
+extern OBJECT * constant_ARGV; /* "ARGV" */
+extern OBJECT * constant_all; /* "all" */
+extern OBJECT * constant_PARALLELISM; /* "PARALLELISM" */
+extern OBJECT * constant_KEEP_GOING; /* "KEEP_GOING" */
+extern OBJECT * constant_other; /* "[OTHER]" */
+extern OBJECT * constant_total; /* "[TOTAL]" */
+extern OBJECT * constant_FILE_DIRSCAN; /* "FILE_DIRSCAN" */
+extern OBJECT * constant_MAIN; /* "MAIN" */
+extern OBJECT * constant_MAIN_MAKE; /* "MAIN_MAKE" */
+extern OBJECT * constant_MAKE_MAKE0; /* "MAKE_MAKE0" */
+extern OBJECT * constant_MAKE_MAKE1; /* "MAKE_MAKE1" */
+extern OBJECT * constant_MAKE_MAKE0SORT; /* "MAKE_MAKE0SORT" */
+extern OBJECT * constant_BINDMODULE; /* "BINDMODULE" */
+extern OBJECT * constant_IMPORT_MODULE; /* "IMPORT_MODULE" */
+extern OBJECT * constant_BUILTIN_GLOB_BACK; /* "BUILTIN_GLOB_BACK" */
+extern OBJECT * constant_timestamp; /* "timestamp" */
+extern OBJECT * constant_python; /* "__python__" */
+extern OBJECT * constant_python_interface; /* "python_interface" */
+extern OBJECT * constant_extra_pythonpath; /* "EXTRA_PYTHONPATH" */
+extern OBJECT * constant_MAIN_PYTHON; /* "MAIN_PYTHON" */
+
+#endif
diff --git a/tools/build/v2/engine/debug.c b/tools/build/v2/engine/debug.c
index 7290555a74..827356bb83 100644
--- a/tools/build/v2/engine/debug.c
+++ b/tools/build/v2/engine/debug.c
@@ -14,34 +14,41 @@
static profile_frame * profile_stack = 0;
static struct hash * profile_hash = 0;
-static profile_info profile_other = { "[OTHER]", 0, 0, 0, 0, 0 };
-static profile_info profile_total = { "[TOTAL]", 0, 0, 0, 0, 0 };
+static profile_info profile_other = { 0, 0, 0, 0, 0, 0 };
+static profile_info profile_total = { 0, 0, 0, 0, 0, 0 };
-profile_frame * profile_init( char * rulename, profile_frame * frame )
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE ) profile_enter( rulename, frame );
return frame;
}
-void profile_enter( char * rulename, profile_frame * frame )
+void profile_enter( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE )
{
clock_t start = clock();
- profile_info info;
- profile_info * p = &info;
-
- if ( !rulename ) p = &profile_other;
+ profile_info * p;
if ( !profile_hash && rulename )
profile_hash = hashinit( sizeof( profile_info ), "profile" );
- info.name = rulename;
-
- if ( rulename && hashenter( profile_hash, (HASHDATA * *)&p ) )
- p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ if ( rulename )
+ {
+ int found;
+ p = (profile_info *)hash_insert( profile_hash, rulename, &found );
+ if ( !found )
+ {
+ p->name = rulename;
+ p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ }
+ }
+ else
+ {
+ p = &profile_other;
+ }
++p->num_entries;
++p->stack_count;
@@ -115,7 +122,7 @@ static void dump_profile_entry( void * p_, void * ignored )
profile_total.memory += p->memory;
}
printf( "%10ld %12.6f %12.6f %12.8f %10ld %10ld %s\n", p->num_entries,
- cumulative, net, q, p->memory, mem_each, p->name );
+ cumulative, net, q, p->memory, mem_each, object_str( p->name ) );
}
@@ -126,7 +133,9 @@ void profile_dump()
printf( "%10s %12s %12s %12s %10s %10s %s\n", "--count--", "--gross--",
"--net--", "--each--", "--mem--", "--each--", "--name--" );
hashenumerate( profile_hash, dump_profile_entry, 0 );
+ profile_other.name = constant_other;
dump_profile_entry( &profile_other, 0 );
+ profile_total.name = constant_total;
dump_profile_entry( &profile_total, (void *)1 );
}
}
diff --git a/tools/build/v2/engine/debug.h b/tools/build/v2/engine/debug.h
index 115a88735b..baad262a00 100644
--- a/tools/build/v2/engine/debug.h
+++ b/tools/build/v2/engine/debug.h
@@ -6,6 +6,7 @@
#ifndef BJAM_DEBUG_H
#define BJAM_DEBUG_H
+#include "constants.h"
#include "jam.h"
#include <time.h>
@@ -13,7 +14,7 @@
struct profile_info
{
/* name of rule being called */
- char* name;
+ OBJECT * name;
/* cumulative time spent in rule */
clock_t cumulative;
/* time spent in rule proper */
@@ -42,13 +43,13 @@ struct profile_frame
};
typedef struct profile_frame profile_frame;
-profile_frame * profile_init( char * rulename, profile_frame * frame );
-void profile_enter( char* rulename, profile_frame * frame );
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame );
+void profile_enter( OBJECT * rulename, profile_frame * frame );
void profile_memory( long mem );
void profile_exit( profile_frame * frame );
void profile_dump();
-#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( #scope, &PROF_ ## scope )
+#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( constant_ ## scope, &PROF_ ## scope )
#define PROFILE_EXIT( scope ) profile_exit( PROF_ ## scope ## _p )
#endif
diff --git a/tools/build/v2/engine/execcmd.h b/tools/build/v2/engine/execcmd.h
index 67f2b839c6..9d3cff35b2 100644
--- a/tools/build/v2/engine/execcmd.h
+++ b/tools/build/v2/engine/execcmd.h
@@ -28,16 +28,18 @@ typedef struct timing_info
void exec_cmd
(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
+ const char * string,
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
);
int exec_wait();
+void exec_done( void );
+
#define EXEC_CMD_OK 0
#define EXEC_CMD_FAIL 1
#define EXEC_CMD_INTR 2
diff --git a/tools/build/v2/engine/execmac.c b/tools/build/v2/engine/execmac.c
deleted file mode 100644
index 2ddddedd15..0000000000
--- a/tools/build/v2/engine/execmac.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-#include <errno.h>
-
-#ifdef OS_MAC
-
-/*
- * execunix.c - execute a shell script on UNIX
- *
- * If $(JAMSHELL) is defined, uses that to formulate execvp().
- * The default is:
- *
- * /bin/sh -c %
- *
- * Each word must be an individual element in a jam variable value.
- *
- * In $(JAMSHELL), % expands to the command string and ! expands to
- * the slot number (starting at 1) for multiprocess (-j) invocations.
- * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
- * argument.
- *
- * Don't just set JAMSHELL to /bin/sh - it won't work!
- *
- * External routines:
- * exec_cmd() - launch an async command execution.
- * exec_wait() - wait and drive at most one execution completion.
- *
- * Internal routines:
- * onintr() - bump intr to note command interruption.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 05/04/94 (seiwald) - async multiprocess interface
- * 01/22/95 (seiwald) - $(JAMSHELL) support
- */
-
-
-/*
- * exec_cmd() - launch an async command execution.
- */
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell
-)
-{
- printf( "%s", string );
- (*func)( closure, EXEC_CMD_OK );
-}
-
-/*
- * exec_wait() - wait and drive at most one execution completion.
- */
-
-int exec_wait()
-{
- return 0;
-}
-
-#endif /* OS_MAC */
diff --git a/tools/build/v2/engine/execnt.c b/tools/build/v2/engine/execnt.c
index 7642045180..f34b378549 100644
--- a/tools/build/v2/engine/execnt.c
+++ b/tools/build/v2/engine/execnt.c
@@ -65,13 +65,13 @@
int maxline();
/* delete and argv list */
-static void free_argv(char**);
+static void free_argv(const char * *);
/* Convert a command string into arguments for spawnvp. */
-static char** string_to_args(const char*);
+static const char** string_to_args(const char*);
/* bump intr to note command interruption */
static void onintr(int);
/* If the command is suitable for execution via spawnvp */
-long can_spawn(char*);
+long can_spawn(const char*);
/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */
static FILETIME add_64(
unsigned long h1, unsigned long l1,
@@ -135,7 +135,7 @@ static struct
int exit_reason; /* reason why a command completed */
/* Function called when the command completes. */
- void (* func)( void * closure, int status, timing_info *, char *, char * );
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * );
/* Opaque data passed back to the 'func' callback called when the command
* completes.
@@ -184,7 +184,7 @@ void execnt_unit_test()
/* Work around vc6 bug; it doesn't like escaped string
* literals inside assert
*/
- char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
+ const char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
char const expected[] = "-c -I\"Foobar\"";
assert( !strcmp( argv[ 0 ], "g++" ) );
@@ -201,26 +201,26 @@ void execnt_unit_test()
void exec_cmd
(
- char * command,
- void (* func)( void * closure, int status, timing_info *, char * invoked_command, char * command_output ),
- void * closure,
- LIST * shell,
- char * action,
- char * target
+ const char * command,
+ void (* func)( void * closure, int status, timing_info *, const char * invoked_command, const char * command_output ),
+ void * closure,
+ LIST * shell,
+ const char * action,
+ const char * target
)
{
int slot;
int raw_cmd = 0 ;
- char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
- char * * argv = argv_static;
+ const char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
+ const char * * argv = argv_static;
char * p;
- char * command_orig = command;
+ const char * command_orig = command;
/* Check to see if we need to hack around the line-length limitation. Look
* for a JAMSHELL setting of "%", indicating that the command should be
* invoked directly.
*/
- if ( shell && !strcmp( shell->string, "%" ) && !list_next( shell ) )
+ if ( !list_empty( shell ) && !strcmp( object_str( list_front( shell ) ), "%" ) && list_next( list_begin( shell ) ) == list_end( shell ) )
{
raw_cmd = 1;
shell = 0;
@@ -290,8 +290,8 @@ void exec_cmd
if ( DEBUG_EXECCMD )
{
- if ( shell )
- printf( "using user-specified shell: %s", shell->string );
+ if ( !list_empty( shell ) )
+ printf( "using user-specified shell: %s", object_str( list_front( shell ) ) );
else
printf( "Executing through .bat file\n" );
}
@@ -305,16 +305,17 @@ void exec_cmd
int i;
char jobno[ 4 ];
int gotpercent = 0;
+ LISTITER shell_iter = list_begin( shell ), shell_end = list_end( shell );
sprintf( jobno, "%d", slot + 1 );
- for ( i = 0; shell && ( i < MAXARGC ); ++i, shell = list_next( shell ) )
+ for ( i = 0; shell_iter != shell_end && ( i < MAXARGC ); ++i, shell_iter = list_next( shell_iter ) )
{
- switch ( shell->string[ 0 ] )
+ switch ( object_str( list_item( shell_iter ) )[ 0 ] )
{
case '%': argv[ i ] = command; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( shell_iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -425,7 +426,7 @@ void exec_cmd
/* Put together the command we run. */
{
- char * * argp = argv;
+ const char * * argp = argv;
string_new( &cmd );
string_copy( &cmd, *(argp++) );
while ( *argp )
@@ -577,10 +578,10 @@ int exec_wait()
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static void free_argv( char * * args )
+static void free_argv( const char * * args )
{
- BJAM_FREE( args[ 0 ] );
- BJAM_FREE( args );
+ BJAM_FREE( (void *)args[ 0 ] );
+ BJAM_FREE( (void *)args );
}
@@ -613,14 +614,14 @@ int maxline()
* New strategy: break the string in at most one place.
*/
-static char * * string_to_args( char const * string )
+static const char * * string_to_args( char const * string )
{
int src_len;
int in_quote;
char * line;
char const * src;
char * dst;
- char * * argv;
+ const char * * argv;
/* Drop leading and trailing whitespace if any. */
while ( isspace( *string ) )
@@ -640,7 +641,7 @@ static char * * string_to_args( char const * string )
* element 1: stores the command-line arguments to the executable
* element 2: NULL terminator
*/
- argv = (char * *)BJAM_MALLOC( 3 * sizeof( char * ) );
+ argv = (const char * *)BJAM_MALLOC( 3 * sizeof( const char * ) );
if ( !argv )
{
BJAM_FREE( line );
@@ -697,9 +698,9 @@ static void onintr( int disp )
* Otherwise, return zero.
*/
-long can_spawn( char * command )
+long can_spawn( const char * command )
{
- char * p;
+ const char * p;
char inquote = 0;
/* Move to the first non-whitespace. */
@@ -1293,4 +1294,10 @@ static void close_alert( HANDLE process )
}
}
+
+void exec_done( void )
+{
+}
+
+
#endif /* USE_EXECNT */
diff --git a/tools/build/v2/engine/execunix.c b/tools/build/v2/engine/execunix.c
index ef9dba0037..147d051cd5 100644
--- a/tools/build/v2/engine/execunix.c
+++ b/tools/build/v2/engine/execunix.c
@@ -88,7 +88,7 @@ static struct
char *target; /* buffer to hold action and target invoked */
char *command; /* buffer to hold command being invoked */
char *buffer[2]; /* buffer to hold stdout and stderr, if any */
- void (*func)( void *closure, int status, timing_info*, char *, char * );
+ void (*func)( void *closure, int status, timing_info*, const char *, const char * );
void *closure;
time_t start_dt; /* start of command timestamp */
} cmdtab[ MAXJOBS ] = {{0}};
@@ -110,12 +110,12 @@ void onintr( int disp )
void exec_cmd
(
- char * string,
- void (*func)( void *closure, int status, timing_info*, char *, char * ),
+ const char * string,
+ void (*func)( void *closure, int status, timing_info*, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
)
{
static int initialized = 0;
@@ -123,7 +123,7 @@ void exec_cmd
int err[2];
int slot;
int len;
- char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
+ const char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
/* Find a slot in the running commands table for this one. */
for ( slot = 0; slot < MAXJOBS; ++slot )
@@ -139,21 +139,22 @@ void exec_cmd
/* Forumulate argv. If shell was defined, be prepared for % and ! subs.
* Otherwise, use stock /bin/sh on unix or cmd.exe on NT.
*/
- if ( shell )
+ if ( !list_empty( shell ) )
{
int i;
char jobno[4];
int gotpercent = 0;
+ LISTITER iter = list_begin( shell ), end = list_end( shell );
sprintf( jobno, "%d", slot + 1 );
- for ( i = 0; shell && i < MAXARGC; ++i, shell = list_next( shell ) )
+ for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) )
{
- switch ( shell->string[0] )
+ switch ( object_str( list_item( iter ) )[0] )
{
case '%': argv[ i ] = string; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -242,7 +243,7 @@ void exec_cmd
setrlimit( RLIMIT_CPU, &r_limit );
}
setpgid( pid,pid );
- execvp( argv[0], argv );
+ execvp( argv[0], (char * *)argv );
perror( "execvp" );
_exit( 127 );
}
@@ -566,4 +567,15 @@ int exec_wait()
return 1;
}
+void exec_done( void )
+{
+ int i;
+ for( i = 0; i < MAXJOBS; ++i )
+ {
+ if( ! cmdtab[i].action ) break;
+ BJAM_FREE( cmdtab[i].action );
+ BJAM_FREE( cmdtab[i].target );
+ }
+}
+
# endif /* USE_EXECUNIX */
diff --git a/tools/build/v2/engine/execvms.c b/tools/build/v2/engine/execvms.c
deleted file mode 100644
index 729917d356..0000000000
--- a/tools/build/v2/engine/execvms.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-
-#ifdef OS_VMS
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <iodef.h>
-#include <ssdef.h>
-#include <descrip.h>
-#include <dvidef.h>
-#include <clidef.h>
-
-/*
- * execvms.c - execute a shell script, ala VMS.
- *
- * The approach is this:
- *
- * If the command is a single line, and shorter than WRTLEN (what we believe to
- * be the maximum line length), we just system() it.
- *
- * If the command is multi-line, or longer than WRTLEN, we write the command
- * block to a temp file, splitting long lines (using "-" at the end of the line
- * to indicate contiuation), and then source that temp file. We use special
- * logic to make sure we do not continue in the middle of a quoted string.
- *
- * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
- * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
- * 01/14/96 (seiwald) - do not put -'s between "'s
- */
-
-#define WRTLEN 240
-
-#define MIN( a, b ) ((a) < (b) ? (a) : (b))
-
-/* 1 for the @ and 4 for the .com */
-
-char tempnambuf[ L_tmpnam + 1 + 4 ] = { 0 };
-
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell,
- char * rule_name,
- char * target
-)
-{
- char * s;
- char * e;
- cahr * p;
- int rstat = EXEC_CMD_OK;
- int status;
-
- /* See if string is more than one line discounting leading/trailing white
- * space.
- */
- for ( s = string; *s && isspace( *s ); ++s );
-
- e = p = strchr( s, '\n' );
-
- while ( p && isspace( *p ) )
- ++p;
-
- /* If multi line or long, write to com file. Otherwise, exec directly. */
- if ( ( p && *p ) || ( e - s > WRTLEN ) )
- {
- FILE * f;
-
- /* Create temp file invocation "@sys$scratch:tempfile.com". */
- if ( !*tempnambuf )
- {
- tempnambuf[0] = '@';
- (void)tmpnam( tempnambuf + 1 );
- strcat( tempnambuf, ".com" );
- }
-
- /* Open tempfile. */
- if ( !( f = fopen( tempnambuf + 1, "w" ) ) )
- {
- printf( "can't open command file\n" );
- (*func)( closure, EXEC_CMD_FAIL );
- return;
- }
-
- /* For each line of the string. */
- while ( *string )
- {
- char * s = strchr( string, '\n' );
- int len = s ? s + 1 - string : strlen( string );
-
- fputc( '$', f );
-
- /* For each chunk of a line that needs to be split. */
- while ( len > 0 )
- {
- char * q = string;
- char * qe = string + MIN( len, WRTLEN );
- char * qq = q;
- int quote = 0;
-
- /* Look for matching "s. */
- for ( ; q < qe; ++q )
- if ( ( *q == '"' ) && ( quote = !quote ) )
- qq = q;
-
- /* Back up to opening quote, if in one. */
- if ( quote )
- q = qq;
-
- fwrite( string, ( q - string ), 1, f );
-
- len -= ( q - string );
- string = q;
-
- if ( len )
- {
- fputc( '-', f );
- fputc( '\n', f );
- }
- }
- }
-
- fclose( f );
-
- status = system( tempnambuf ) & 0x07;
-
- unlink( tempnambuf + 1 );
- }
- else
- {
- /* Execute single line command. Strip trailing newline before execing.
- */
- if ( e ) *e = 0;
- status = system( s ) & 0x07;
- }
-
- /* Fail for error or fatal error. OK on OK, warning or info exit. */
- if ( ( status == 2 ) || ( status == 4 ) )
- rstat = EXEC_CMD_FAIL;
-
- (*func)( closure, rstat );
-}
-
-
-int exec_wait()
-{
- return 0;
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/expand.c b/tools/build/v2/engine/expand.c
deleted file mode 100644
index d8e58827c6..0000000000
--- a/tools/build/v2/engine/expand.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "lists.h"
-# include "variable.h"
-# include "expand.h"
-# include "pathsys.h"
-# include "newstr.h"
-# include <assert.h>
-# include <stdlib.h>
-# include <limits.h>
-
-# ifdef OS_CYGWIN
-# include <sys/cygwin.h>
-# include <windows.h>
-# endif
-
-/*
- * expand.c - expand a buffer, given variable values
- *
- * External routines:
- *
- * var_expand() - variable-expand input string into list of strings
- *
- * Internal routines:
- *
- * var_edit_parse() - parse : modifiers into PATHNAME structure.
- * var_edit_file() - copy input target name to output, modifying filename.
- * var_edit_shift() - do upshift/downshift mods.
- *
- * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
- */
-
-typedef struct
-{
- PATHNAME f; /* :GDBSMR -- pieces */
- char parent; /* :P -- go to parent directory */
- char filemods; /* one of the above applied */
- char downshift; /* :L -- downshift result */
- char upshift; /* :U -- upshift result */
- char to_slashes; /* :T -- convert "\" to "/" */
- char to_windows; /* :W -- convert cygwin to native paths */
- PATHPART empty; /* :E -- default for empties */
- PATHPART join; /* :J -- join list with char */
-} VAR_EDITS ;
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits );
-static void var_edit_file ( char * in, string * out, VAR_EDITS * edits );
-static void var_edit_shift( string * out, VAR_EDITS * edits );
-
-#define MAGIC_COLON '\001'
-#define MAGIC_LEFT '\002'
-#define MAGIC_RIGHT '\003'
-
-
-/*
- * var_expand() - variable-expand input string into list of strings.
- *
- * Would just copy input to output, performing variable expansion, except that
- * since variables can contain multiple values the result of variable expansion
- * may contain multiple values (a list). Properly performs "product" operations
- * that occur in "$(var1)xxx$(var2)" or even "$($(var2))".
- *
- * Returns a newly created list.
- */
-
-LIST * var_expand( LIST * l, char * in, char * end, LOL * lol, int cancopyin )
-{
- char out_buf[ MAXSYM ];
- string buf[ 1 ];
- string out1[ 1 ]; /* temporary buffer */
- size_t prefix_length;
- char * out;
- char * inp = in;
- char * ov; /* for temp copy of variable in outbuf */
- int depth;
-
- if ( DEBUG_VAREXP )
- printf( "expand '%.*s'\n", end - in, in );
-
- /* This gets a lot of cases: $(<) and $(>). */
- if
- (
- ( in[ 0 ] == '$' ) &&
- ( in[ 1 ] == '(' ) &&
- ( in[ 3 ] == ')' ) &&
- ( in[ 4 ] == '\0' )
- )
- {
- switch ( in[ 2 ] )
- {
- case '<': return list_copy( l, lol_get( lol, 0 ) );
- case '>': return list_copy( l, lol_get( lol, 1 ) );
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[ 2 ] - '1' ) );
- }
- }
- else if ( in[0] == '$' && in[1] == '(' && in[2] == '1' && in[4] == ')' &&
- in[5] == '\0') {
-
- switch( in[3] )
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[3]-'0'+10-1 ) );
- }
- }
-
- /* Expand @() files, to single item plus accompanying file. */
- if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) && ( *( end - 1 ) == ')' ) )
- {
- /* We try the expansion until it fits within the propective output
- * buffer.
- */
- char * at_buf = 0;
- int at_size = MAXJPATH;
- int at_len = 0;
- do
- {
- BJAM_FREE( at_buf );
- at_buf = (char *)BJAM_MALLOC_ATOMIC( at_size + 1 );
- at_len = var_string( in, at_buf, at_size, lol );
- at_size *= 2;
- }
- while ( ( at_len < 0 ) && ( at_size < INT_MAX / 2 ) );
- /* Return the result as a single item list. */
- if ( at_len > 0 )
- {
- LIST * r;
- string_copy( buf, at_buf );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- BJAM_FREE( at_buf );
- return r;
- }
- BJAM_FREE( at_buf );
- }
-
- /* Just try simple copy of in to out. */
- while ( in < end )
- if ( ( *in++ == '$' ) && ( *in == '(' ) )
- goto expand;
-
- /* No variables expanded - just add copy of input string to list. */
-
- /* 'cancopyin' is an optimization: if the input was already a list item, we
- * can use copystr() to put it on the new list. Otherwise, we use the slower
- * newstr().
- */
- if ( cancopyin )
- return list_new( l, copystr( inp ) );
-
- {
- LIST * r;
- string_new( buf );
- string_append_range( buf, inp, end );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- return r;
- }
-
-expand:
- string_new( buf );
- string_append_range( buf, inp, in - 1 ); /* Copy the part before '$'. */
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf $
- * ^ ^
- * out_buf out
- *
- *
- * We just copied the $ of $(...), so back up one on the output. We now find
- * the matching close paren, copying the variable and modifiers between the
- * $( and ) temporarily into out_buf, so that we can replace :'s with
- * MAGIC_COLON. This is necessary to avoid being confused by modifier values
- * that are variables containing :'s. Ugly.
- */
-
- depth = 1;
- inp = ++in; /* Skip over the '('. */
-
- while ( ( in < end ) && depth )
- {
- switch ( *in++ )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^ ^
- * inp in end
- */
- prefix_length = buf->size;
- string_append_range( buf, inp, in - 1 );
-
- out = buf->value + prefix_length;
- for ( ov = out; ov < buf->value + buf->size; ++ov )
- {
- switch ( *ov )
- {
- case ':': *ov = MAGIC_COLON; break;
- case '[': *ov = MAGIC_LEFT ; break;
- case ']': *ov = MAGIC_RIGHT; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf variable
- * ^ ^ ^
- * out_buf out ov
- *
- * Later we will overwrite 'variable' in out_buf, but we will be done with
- * it by then. 'variable' may be a multi-element list, so may each value for
- * '$(variable element)', and so may 'remainder'. Thus we produce a product
- * of three lists.
- */
- {
- LIST * variables = 0;
- LIST * remainder = 0;
- LIST * vars;
-
- /* Recursively expand variable name & rest of input. */
- if ( out < ov ) variables = var_expand( L0, out, ov, lol, 0 );
- if ( in < end ) remainder = var_expand( L0, in, end, lol, 0 );
-
- /* Now produce the result chain. */
-
- /* For each variable name. */
- for ( vars = variables; vars; vars = list_next( vars ) )
- {
- LIST * value = 0;
- LIST * evalue = 0;
- char * colon;
- char * bracket;
- string variable[1];
- char * varname;
- int sub1 = 0;
- int sub2 = -1;
- VAR_EDITS edits;
-
- /* Look for a : modifier in the variable name. Must copy into
- * varname so we can modify it.
- */
- string_copy( variable, vars->string );
- varname = variable->value;
-
- if ( ( colon = strchr( varname, MAGIC_COLON ) ) )
- {
- string_truncate( variable, colon - varname );
- var_edit_parse( colon + 1, &edits );
- }
-
- /* Look for [x-y] subscripting. sub1 and sub2 are x and y. */
- if ( ( bracket = strchr( varname, MAGIC_LEFT ) ) )
- {
- /* Make all syntax errors in [] subscripting result in the same
- * behavior: silenty return an empty expansion (by setting sub2
- * = 0). Brute force parsing; May get moved into yacc someday.
- */
-
- char * s = bracket + 1;
-
- string_truncate( variable, bracket - varname );
-
- do /* so we can use "break" */
- {
- /* Allow negative indexes. */
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
- sub1 = atoi( s );
-
- /* Skip over the first symbol, which is either a digit or dash. */
- ++s;
- while ( isdigit( *s ) ) ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = sub1;
- break;
- }
-
- if ( *s != '-' )
- {
- sub2 = 0;
- break;
- }
-
- ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = -1;
- break;
- }
-
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
-
- /* First, compute the index of the last element. */
- sub2 = atoi( s );
- while ( isdigit( *++s ) );
-
- if ( *s != MAGIC_RIGHT )
- sub2 = 0;
-
- } while ( 0 );
-
- /* Anything but the end of the string, or the colon introducing
- * a modifier is a syntax error.
- */
- ++s;
- if ( *s && ( *s != MAGIC_COLON ) )
- sub2 = 0;
-
- *bracket = '\0';
- }
-
- /* Get variable value, with special handling for $(<), $(>), $(n).
- */
- if ( !varname[1] )
- {
- if ( varname[0] == '<' )
- value = lol_get( lol, 0 );
- else if ( varname[0] == '>' )
- value = lol_get( lol, 1 );
- else if ( ( varname[0] >= '1' ) && ( varname[0] <= '9' ) )
- value = lol_get( lol, varname[0] - '1' );
- else if( varname[0] == '1' && varname[1] >= '0' &&
- varname[1] <= '9' && !varname[2] )
- value = lol_get( lol, varname[1] - '0' + 10 - 1 );
- }
-
- if ( !value )
- value = var_get( varname );
-
- /* Handle negitive indexes: part two. */
- {
- int length = list_length( value );
-
- if ( sub1 < 0 )
- sub1 = length + sub1;
- else
- sub1 -= 1;
-
- if ( sub2 < 0 )
- sub2 = length + 1 + sub2 - sub1;
- else
- sub2 -= sub1;
- /* The "sub2 < 0" test handles the semantic error of sub2 <
- * sub1.
- */
- if ( sub2 < 0 )
- sub2 = 0;
- }
-
- /* The fast path: $(x) - just copy the variable value. This is only
- * an optimization.
- */
- if ( ( out == out_buf ) && !bracket && !colon && ( in == end ) )
- {
- string_free( variable );
- l = list_copy( l, value );
- continue;
- }
-
- /* Handle start subscript. */
- while ( ( sub1 > 0 ) && value )
- --sub1, value = list_next( value );
-
- /* Empty w/ :E=default?. */
- if ( !value && colon && edits.empty.ptr )
- evalue = value = list_new( L0, newstr( edits.empty.ptr ) );
-
- /* For each variable value. */
- string_new( out1 );
- for ( ; value; value = list_next( value ) )
- {
- LIST * rem;
- size_t postfix_start;
-
- /* Handle end subscript (length actually). */
-
- if ( sub2 >= 0 && --sub2 < 0 )
- break;
-
- string_truncate( buf, prefix_length );
-
- /* Apply : mods, if present */
-
- if ( colon && edits.filemods )
- var_edit_file( value->string, out1, &edits );
- else
- string_append( out1, value->string );
-
- if ( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) )
- var_edit_shift( out1, &edits );
-
- /* Handle :J=joinval */
- /* If we have more values for this var, just keep appending them
- * (using the join value) rather than creating separate LIST
- * elements.
- */
- if ( colon && edits.join.ptr &&
- ( list_next( value ) || list_next( vars ) ) )
- {
- string_append( out1, edits.join.ptr );
- continue;
- }
-
- string_append( buf, out1->value );
- string_free( out1 );
- string_new( out1 );
-
- /* If no remainder, append result to output chain. */
- if ( in == end )
- {
- l = list_new( l, newstr( buf->value ) );
- continue;
- }
-
- /* For each remainder, append the complete string to the output
- * chain. Remember the end of the variable expansion so we can
- * just tack on each instance of 'remainder'.
- */
- postfix_start = buf->size;
- for ( rem = remainder; rem; rem = list_next( rem ) )
- {
- string_truncate( buf, postfix_start );
- string_append( buf, rem->string );
- l = list_new( l, newstr( buf->value ) );
- }
- }
- string_free( out1 );
-
- /* Toss used empty. */
- if ( evalue )
- list_free( evalue );
-
- string_free( variable );
- }
-
- /* variables & remainder were gifts from var_expand and must be freed. */
- if ( variables ) list_free( variables );
- if ( remainder ) list_free( remainder );
-
- if ( DEBUG_VAREXP )
- {
- printf( "expanded to " );
- list_print( l );
- printf( "\n" );
- }
-
- string_free( buf );
- return l;
- }
-}
-
-
-/*
- * var_edit_parse() - parse : modifiers into PATHNAME structure
- *
- * The : modifiers in a $(varname:modifier) currently support replacing or
- * omitting elements of a filename, and so they are parsed into a PATHNAME
- * structure (which contains pointers into the original string).
- *
- * Modifiers of the form "X=value" replace the component X with the given value.
- * Modifiers without the "=value" cause everything but the component X to be
- * omitted. X is one of:
- *
- * G <grist>
- * D directory name
- * B base name
- * S .suffix
- * M (member)
- * R root directory - prepended to whole path
- *
- * This routine sets:
- *
- * f->f_xxx.ptr = 0
- * f->f_xxx.len = 0
- * -> leave the original component xxx
- *
- * f->f_xxx.ptr = string
- * f->f_xxx.len = strlen( string )
- * -> replace component xxx with string
- *
- * f->f_xxx.ptr = ""
- * f->f_xxx.len = 0
- * -> omit component xxx
- *
- * var_edit_file() below and path_build() obligingly follow this convention.
- */
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits )
-{
- int havezeroed = 0;
- memset( (char *)edits, 0, sizeof( *edits ) );
-
- while ( *mods )
- {
- char * p;
- PATHPART * fp;
-
- switch ( *mods++ )
- {
- case 'L': edits->downshift = 1; continue;
- case 'U': edits->upshift = 1; continue;
- case 'P': edits->parent = edits->filemods = 1; continue;
- case 'E': fp = &edits->empty; goto strval;
- case 'J': fp = &edits->join; goto strval;
- case 'G': fp = &edits->f.f_grist; goto fileval;
- case 'R': fp = &edits->f.f_root; goto fileval;
- case 'D': fp = &edits->f.f_dir; goto fileval;
- case 'B': fp = &edits->f.f_base; goto fileval;
- case 'S': fp = &edits->f.f_suffix; goto fileval;
- case 'M': fp = &edits->f.f_member; goto fileval;
- case 'T': edits->to_slashes = 1; continue;
- case 'W': edits->to_windows = 1; continue;
- default:
- return; /* Should complain, but so what... */
- }
-
- fileval:
- /* Handle :CHARS, where each char (without a following =) selects a
- * particular file path element. On the first such char, we deselect all
- * others (by setting ptr = "", len = 0) and for each char we select
- * that element (by setting ptr = 0).
- */
- edits->filemods = 1;
-
- if ( *mods != '=' )
- {
- if ( !havezeroed++ )
- {
- int i;
- for ( i = 0; i < 6; ++i )
- {
- edits->f.part[ i ].len = 0;
- edits->f.part[ i ].ptr = "";
- }
- }
-
- fp->ptr = 0;
- continue;
- }
-
- strval:
- /* Handle :X=value, or :X */
- if ( *mods != '=' )
- {
- fp->ptr = "";
- fp->len = 0;
- }
- else if ( ( p = strchr( mods, MAGIC_COLON ) ) )
- {
- *p = 0;
- fp->ptr = ++mods;
- fp->len = p - mods;
- mods = p + 1;
- }
- else
- {
- fp->ptr = ++mods;
- fp->len = strlen( mods );
- mods += fp->len;
- }
- }
-}
-
-
-/*
- * var_edit_file() - copy input target name to output, modifying filename.
- */
-
-static void var_edit_file( char * in, string * out, VAR_EDITS * edits )
-{
- PATHNAME pathname;
-
- /* Parse apart original filename, putting parts into "pathname". */
- path_parse( in, &pathname );
-
- /* Replace any pathname with edits->f */
- if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
- if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
- if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
- if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
- if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
- if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
-
- /* If requested, modify pathname to point to parent. */
- if ( edits->parent )
- path_parent( &pathname );
-
- /* Put filename back together. */
- path_build( &pathname, out, 0 );
-}
-
-
-/*
- * var_edit_shift() - do upshift/downshift mods.
- */
-
-static void var_edit_shift( string * out, VAR_EDITS * edits )
-{
- /* Handle upshifting, downshifting and slash translation now. */
- char * p;
- for ( p = out->value; *p; ++p)
- {
- if ( edits->upshift )
- *p = toupper( *p );
- else if ( edits->downshift )
- *p = tolower( *p );
- if ( edits->to_slashes && ( *p == '\\' ) )
- *p = '/';
-# ifdef OS_CYGWIN
- if ( edits->to_windows )
- {
- char result[ MAX_PATH + 1 ];
- cygwin_conv_to_win32_path( out->value, result );
- assert( strlen( result ) <= MAX_PATH );
- string_free( out );
- string_copy( out, result );
- }
-# endif
- }
- out->size = p - out->value;
-}
-
-
-#ifndef NDEBUG
-void var_expand_unit_test()
-{
- LOL lol[ 1 ];
- LIST * l;
- LIST * l2;
- LIST * expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
- LIST * e2;
- char axyb[] = "a$(xy)b";
- char azb[] = "a$($(z))b";
- char path[] = "$(p:W)";
-
-# ifdef OS_CYGWIN
- char cygpath[ 256 ];
- cygwin_conv_to_posix_path( "c:\\foo\\bar", cygpath );
-# else
- char cygpath[] = "/cygdrive/c/foo/bar";
-# endif
-
- lol_init(lol);
- var_set( "xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
- var_set( "z", list_new( L0, newstr( "xy" ) ), VAR_SET );
- var_set( "p", list_new( L0, newstr( cygpath ) ), VAR_SET );
-
- l = var_expand( 0, axyb, axyb + sizeof( axyb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, azb, azb + sizeof( azb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, path, path + sizeof( path ) - 1, lol, 0 );
- assert( l != 0 );
- assert( list_next( l ) == 0 );
-# ifdef OS_CYGWIN
- /* On some installations of cygwin the drive letter is expanded to other
- * case. This has been reported to be the case if cygwin has been installed
- * to C:\ as opposed to C:\cygwin. Since case of the drive letter will not
- * matter, we allow for both.
- */
- assert( !strcmp( l->string, "c:\\foo\\bar" ) ||
- !strcmp( l->string, "C:\\foo\\bar" ) );
-# else
- assert( !strcmp( l->string, cygpath ) );
-# endif
- list_free( l );
- list_free( expected );
- lol_free( lol );
-}
-#endif
diff --git a/tools/build/v2/engine/expand.h b/tools/build/v2/engine/expand.h
deleted file mode 100644
index cc25d19090..0000000000
--- a/tools/build/v2/engine/expand.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * expand.h - expand a buffer, given variable values
- */
-
-#include "lists.h"
-
-LIST *var_expand( LIST *l, char *in, char *end, LOL *lol, int cancopyin );
-void var_expand_unit_test();
diff --git a/tools/build/v2/engine/filemac.c b/tools/build/v2/engine/filemac.c
deleted file mode 100644
index e69aa648f3..0000000000
--- a/tools/build/v2/engine/filemac.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-#include <Files.h>
-#include <Folders.h>
-
-# include <:sys:stat.h>
-
-/*
- * filemac.c - manipulate file names and scan directories on macintosh
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/19/94 (mikem) - solaris string table insanity support
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 05/03/96 (seiwald) - split into pathunix.c
- * 11/21/96 (peterk) - BEOS does not have Unix-style archives
- */
-
-
-void CopyC2PStr( char const * cstr, StringPtr pstr )
-{
- int len;
- for ( len = 0; *cstr && ( len < 255 ); pstr[ ++len ] = *cstr++ );
- pstr[ 0 ] = len;
-}
-
-
-/*
- * file_dirscan() - scan a directory for files.
- */
-
-void file_dirscan( char * dir, scanback func, void * closure )
-{
- PATHNAME f;
- string filename[ 1 ];
- unsigned char fullPath[ 512 ];
-
- FSSpec spec;
- WDPBRec vol;
- Str63 volName;
- CInfoPBRec lastInfo;
- int index = 1;
-
- /* First enter directory itself. */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- /* Special case ":" - enter it */
-
- if ( ( f.f_dir.len == 1 ) && ( f.f_dir.ptr[0] == ':' ) )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
-
- /* Now enter contents of directory */
-
- vol.ioNamePtr = volName;
-
- if ( PBHGetVolSync( &vol ) )
- return;
-
- CopyC2PStr( dir, fullPath );
-
- if ( FSMakeFSSpec( vol.ioWDVRefNum, vol.ioWDDirID, fullPath, &spec ) )
- return;
-
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = spec.name;
- lastInfo.dirInfo.ioFDirIndex = 0;
- lastInfo.dirInfo.ioACUser = 0;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- if ( !( lastInfo.dirInfo.ioFlAttrib & 0x10 ) )
- return;
-
- /* ioDrDirID must be reset each time. */
- spec.parID = lastInfo.dirInfo.ioDrDirID;
-
- string_new( filename );
- for ( ; ; )
- {
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = fullPath;
- lastInfo.dirInfo.ioFDirIndex = index++;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- f.f_base.ptr = (char *)fullPath + 1;
- f.f_base.len = *fullPath;
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- string_free( filename );
-}
-
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan().
- */
-
-int file_time( char * filename, time_t * time )
-{
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-
-int file_is_file( char * filename )
-{
- struct stat statbuf;
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
- return S_ISREG( statbuf.st_mode ) ? 1 : 0;
-}
-
-int file_mkdir(char *pathname)
-{
- return mkdir(pathname, 0766);
-}
-
-
-/*
- * file_archscan() - scan an archive for files.
- */
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
-}
-
-
-# endif /* macintosh */
diff --git a/tools/build/v2/engine/filent.c b/tools/build/v2/engine/filent.c
index ab18957677..b448cd03f7 100644
--- a/tools/build/v2/engine/filent.c
+++ b/tools/build/v2/engine/filent.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# ifdef OS_NT
@@ -57,20 +57,19 @@
* file_dirscan() - scan a directory for files
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
file_info_t * d = 0;
- dir = short_path_to_long_path( dir );
-
/* First enter directory itself */
d = file_query( dir );
if ( !d || !d->is_dir )
{
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -84,11 +83,15 @@ void file_dirscan( char * dir, scanback func, void * closure )
int ret;
struct _finddata_t finfo[ 1 ];
LIST * files = L0;
- int d_length = strlen( d->name );
+ int d_length;
+
+ dir = short_path_to_long_path( dir );
+
+ d_length = strlen( object_str( dir ) );
memset( (char *)&f, '\0', sizeof( f ) );
- f.f_dir.ptr = d->name;
+ f.f_dir.ptr = object_str( dir );
f.f_dir.len = d_length;
/* Now enter contents of directory */
@@ -103,8 +106,8 @@ void file_dirscan( char * dir, scanback func, void * closure )
* its trailing path separator or otherwise we would not support the
* Windows root folder specified without its drive letter, i.e. '\'.
*/
- char trailingChar = d->name[ d_length - 1 ] ;
- string_copy( filespec, d->name );
+ char trailingChar = object_str( dir )[ d_length - 1 ] ;
+ string_copy( filespec, object_str( dir ) );
if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
string_append( filespec, "\\" );
string_append( filespec, "*" );
@@ -117,6 +120,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -132,7 +136,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename );
- files = list_new( files, newstr(filename->value) );
+ files = list_push_back( files, object_new(filename->value) );
ff = file_info( filename->value );
ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
@@ -147,6 +151,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = ( handle < 0L ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -154,6 +159,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_new( filename );
while ( !ret )
{
+ OBJECT * filename_obj;
file_info_t * ff = 0;
f.f_base.ptr = finfo->name;
@@ -162,8 +168,10 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr( filename->value ) );
- ff = file_info( filename->value );
+ filename_obj = object_new( filename->value );
+ path_add_key( filename_obj );
+ files = list_push_back( files, filename_obj );
+ ff = file_info( filename_obj );
ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
ff->size = finfo->size;
@@ -176,17 +184,26 @@ void file_dirscan( char * dir, scanback func, void * closure )
# endif
string_free( filename );
string_free( filespec );
+ object_free( dir );
d->files = files;
}
/* Special case \ or d:\ : enter it */
{
- unsigned long len = strlen(d->name);
- if ( len == 1 && d->name[0] == '\\' )
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
- else if ( len == 3 && d->name[1] == ':' ) {
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ unsigned long len = strlen( object_str( d->name ) );
+ if ( len == 1 && object_str( d->name )[0] == '\\' )
+ {
+ OBJECT * dir = short_path_to_long_path( d->name );
+ (*func)( closure, dir, 1 /* stat()'ed */, d->time );
+ object_free( dir );
+ }
+ else if ( len == 3 && object_str( d->name )[1] == ':' )
+ {
+ char buf[4];
+ OBJECT * dir1 = short_path_to_long_path( d->name );
+ OBJECT * dir2;
+ (*func)( closure, dir1, 1 /* stat()'ed */, d->time );
/* We've just entered 3-letter drive name spelling (with trailing
slash), into the hash table. Now enter two-letter variant,
without trailing slash, so that if we try to check whether
@@ -199,34 +216,38 @@ void file_dirscan( char * dir, scanback func, void * closure )
There will be no trailing slash in $(p), but there will be one
in $(p2). But, that seems rather fragile.
*/
- d->name[2] = 0;
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ strcpy( buf, object_str( dir1 ) );
+ buf[2] = 0;
+ dir2 = object_new( buf );
+ (*func)( closure, dir2, 1 /* stat()'ed */, d->time );
+ object_free( dir2 );
+ object_free( dir1 );
}
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
- (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
- files = list_next( files );
+ file_info_t * ff = file_info( list_item( iter ) );
+ (*func)( closure, list_item( iter ), 1 /* stat()'ed */, ff->time );
}
}
PROFILE_EXIT( FILE_DIRSCAN );
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -243,8 +264,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -252,14 +273,14 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char *pathname)
+int file_mkdir( const char * pathname )
{
return _mkdir(pathname);
}
@@ -290,9 +311,9 @@ struct ar_hdr {
void
file_archscan(
- char *archive,
- scanback func,
- void *closure )
+ const char * archive,
+ scanback func,
+ void * closure )
{
struct ar_hdr ar_hdr;
char *string_table = 0;
@@ -320,9 +341,10 @@ file_archscan(
{
long lar_date;
long lar_size;
- char *name = 0;
- char *endname;
- char *c;
+ char * name = 0;
+ char * endname;
+ char * c;
+ OBJECT * member;
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
@@ -375,7 +397,9 @@ file_archscan(
name = c + 1;
sprintf( buf, "%s(%.*s)", archive, endname - name, name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + lar_size;
lseek( fd, offset, 0 );
diff --git a/tools/build/v2/engine/fileos2.c b/tools/build/v2/engine/fileos2.c
deleted file mode 100644
index af2373ea83..0000000000
--- a/tools/build/v2/engine/fileos2.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-/* note that we use "fileunix.c" when compiling with EMX on OS/2 */
-# if defined(OS_OS2) && !defined(__EMX__)
-
-# include <io.h>
-# include <dos.h>
-
-/*
- * fileos2.c - scan directories and archives on NT
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 07/10/95 (taylor) Findfirst() returns the first file on NT.
- * 05/03/96 (seiwald) split apart into pathnt.c
- * 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
- */
-
-/*
- * file_dirscan() - scan a directory for files
- */
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
- PATHNAME f;
- string filespec[1];
- long handle;
- int ret;
- struct _find_t finfo[1];
-
- /* First enter directory itself */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- dir = *dir ? dir : ".";
-
- /* Special case \ or d:\ : enter it */
- string_copy( filespec, dir );
-
- if ( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else if ( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else
- string_push_back( filespec, '/' );
-
- string_push_back( filespec, '*' );
-
- /* Now enter contents of directory */
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", filespec->value );
-
- /* Time info in dos find_t is not very useful. It consists */
- /* of a separate date and time, and putting them together is */
- /* not easy. So we leave that to a later stat() call. */
-
- if ( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
- {
- string filename[1];
- string_new( filename );
- do
- {
- f.f_base.ptr = finfo->name;
- f.f_base.len = strlen( finfo->name );
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- while ( !_dos_findnext( finfo ) );
- string_free( filename );
- }
-}
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan()
- */
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This is called on OS2, not NT. */
- /* NT fills in the time in the dirscan. */
-
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-void
-file_archscan(
- char *archive,
- scanback func,
- void *closure )
-{
-}
-
-# endif /* OS2 && !__EMX__ */
-
diff --git a/tools/build/v2/engine/filesys.c b/tools/build/v2/engine/filesys.c
index eb62ed4060..8d174cfd8b 100644
--- a/tools/build/v2/engine/filesys.c
+++ b/tools/build/v2/engine/filesys.c
@@ -1,7 +1,7 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include "lists.h"
@@ -36,25 +36,30 @@ void file_build1( PATHNAME * f, string * file )
static struct hash * filecache_hash = 0;
static file_info_t filecache_finfo;
-file_info_t * file_info(char * filename)
+file_info_t * file_info( OBJECT * filename )
{
file_info_t *finfo = &filecache_finfo;
+ int found;
if ( !filecache_hash )
filecache_hash = hashinit( sizeof( file_info_t ), "file_info" );
- finfo->name = filename;
- finfo->is_file = 0;
- finfo->is_dir = 0;
- finfo->size = 0;
- finfo->time = 0;
- finfo->files = 0;
- if ( hashenter( filecache_hash, (HASHDATA**)&finfo ) )
+ filename = path_as_key( filename );
+
+ finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
+ if ( !found )
{
/* printf( "file_info: %s\n", filename ); */
- finfo->name = newstr( finfo->name );
+ finfo->name = object_copy( filename );
+ finfo->is_file = 0;
+ finfo->is_dir = 0;
+ finfo->size = 0;
+ finfo->time = 0;
+ finfo->files = L0;
}
+ object_free( filename );
+
return finfo;
}
@@ -62,22 +67,33 @@ static LIST * files_to_remove = L0;
static void remove_files_atexit(void)
{
- /* we do pop front in case this exit function is called
- more than once */
- while ( files_to_remove )
+ LISTITER iter = list_begin( files_to_remove ), end = list_end( files_to_remove );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- remove( files_to_remove->string );
- files_to_remove = list_pop_front( files_to_remove );
+ remove( object_str( list_item( iter ) ) );
}
+ list_free( files_to_remove );
+ files_to_remove = L0;
+}
+
+static void free_file_info ( void * xfile, void * data )
+{
+ file_info_t * file = (file_info_t *)xfile;
+ object_free( file->name );
+ list_free( file->files );
}
void file_done()
{
remove_files_atexit();
- hashdone( filecache_hash );
+ if ( filecache_hash )
+ {
+ hashenumerate( filecache_hash, free_file_info, (void *)0 );
+ hashdone( filecache_hash );
+ }
}
-void file_remove_atexit( const char * path )
+void file_remove_atexit( OBJECT * path )
{
- files_to_remove = list_new( files_to_remove, newstr((char*)path) );
+ files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
}
diff --git a/tools/build/v2/engine/filesys.h b/tools/build/v2/engine/filesys.h
index efc081d120..d32805126e 100644
--- a/tools/build/v2/engine/filesys.h
+++ b/tools/build/v2/engine/filesys.h
@@ -20,22 +20,23 @@
# include "pathsys.h"
#include "hash.h"
#include "lists.h"
+#include "object.h"
-typedef void (*scanback)( void *closure, char *file, int found, time_t t );
+typedef void (*scanback)( void *closure, OBJECT * file, int found, time_t t );
-void file_dirscan( char *dir, scanback func, void *closure );
-void file_archscan( char *arch, scanback func, void *closure );
+void file_dirscan( OBJECT * dir, scanback func, void * closure );
+void file_archscan( const char * arch, scanback func, void * closure );
-int file_time( char *filename, time_t *time );
+int file_time( OBJECT * filename, time_t * time );
void file_build1(PATHNAME *f, string* file) ;
-int file_is_file(char* filename);
-int file_mkdir(char *pathname);
+int file_is_file( OBJECT * filename );
+int file_mkdir( const char * pathname );
typedef struct file_info_t file_info_t ;
struct file_info_t
{
- char * name;
+ OBJECT * name;
short is_file;
short is_dir;
unsigned long size;
@@ -47,14 +48,14 @@ struct file_info_t
/* Creates a pointer to information about file 'filename', creating it as
* necessary. If created, the structure will be default initialized.
*/
-file_info_t * file_info( char * filename );
+file_info_t * file_info( OBJECT * filename );
/* Returns information about a file, queries the OS if needed. */
-file_info_t * file_query( char * filename );
+file_info_t * file_query( OBJECT * filename );
void file_done();
/* Marks a path/file to be removed when jam exits. */
-void file_remove_atexit( const char * path );
+void file_remove_atexit( OBJECT * path );
#endif
diff --git a/tools/build/v2/engine/fileunix.c b/tools/build/v2/engine/fileunix.c
index 680c3f5394..d8b458c9ba 100644
--- a/tools/build/v2/engine/fileunix.c
+++ b/tools/build/v2/engine/fileunix.c
@@ -15,7 +15,7 @@
# include "filesys.h"
# include "strings.h"
# include "pathsys.h"
-# include "newstr.h"
+# include "object.h"
# include <stdio.h>
# include <sys/stat.h>
@@ -125,7 +125,7 @@ struct ar_hdr /* archive file member header - printable ascii */
* file_dirscan() - scan a directory for files.
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
@@ -139,37 +139,39 @@ void file_dirscan( char * dir, scanback func, void * closure )
return;
}
- if ( ! d->files )
+ if ( list_empty( d->files ) )
{
LIST* files = L0;
PATHNAME f;
DIR *dd;
STRUCT_DIRENT *dirent;
string filename[1];
+ const char * dirstr = object_str( dir );
/* First enter directory itself */
memset( (char *)&f, '\0', sizeof( f ) );
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
+ f.f_dir.ptr = dirstr;
+ f.f_dir.len = strlen( dirstr );
- dir = *dir ? dir : ".";
+ dirstr = *dirstr ? dirstr : ".";
/* Now enter contents of directory. */
- if ( !( dd = opendir( dir ) ) )
+ if ( !( dd = opendir( dirstr ) ) )
{
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
+ printf( "scan directory %s\n", dirstr );
string_new( filename );
while ( ( dirent = readdir( dd ) ) )
{
+ OBJECT * filename_obj;
# ifdef old_sinix
/* Broken structure definition on sinix. */
f.f_base.ptr = dirent->d_name - 2;
@@ -181,8 +183,9 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr(filename->value) );
- file_query( filename->value );
+ filename_obj = object_new( filename->value );
+ files = list_push_back( files, filename_obj );
+ file_query( filename_obj );
}
string_free( filename );
@@ -193,18 +196,18 @@ void file_dirscan( char * dir, scanback func, void * closure )
/* Special case / : enter it */
{
- unsigned long len = strlen(d->name);
- if ( ( len == 1 ) && ( d->name[0] == '/' ) )
+ if ( strcmp( object_str( d->name ), "/" ) == 0 )
(*func)( closure, d->name, 1 /* stat()'ed */, d->time );
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
+ file_info_t * ff = file_info( list_item( iter ) );
(*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
files = list_next( files );
}
@@ -214,14 +217,14 @@ void file_dirscan( char * dir, scanback func, void * closure )
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -238,8 +241,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -247,16 +250,16 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char* pathname)
+int file_mkdir( const char * pathname )
{
- return mkdir(pathname, 0766);
+ return mkdir( pathname, 0766 );
}
/*
@@ -270,9 +273,9 @@ int file_mkdir(char* pathname)
void
file_archscan(
- char *archive,
+ const char * archive,
scanback func,
- void *closure )
+ void * closure )
{
# ifndef NO_AR
struct ar_hdr ar_hdr;
@@ -312,6 +315,7 @@ file_archscan(
char * c;
char * src;
char * dest;
+ OBJECT * member;
strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
@@ -356,14 +360,16 @@ file_archscan(
sprintf( buf, "%s(%s)", archive, lar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
lseek( fd, offset, 0 );
}
- if (string_table)
- BJAM_FREE(string_table);
+ if ( string_table )
+ BJAM_FREE( string_table );
close( fd );
@@ -396,10 +402,11 @@ static void file_archscan_small(
while ( ( offset > 0 )
&& ( lseek( fd, offset, 0 ) >= 0 )
- && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
+ && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) )
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date );
@@ -412,7 +419,9 @@ static void file_archscan_small(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
@@ -446,6 +455,7 @@ static void file_archscan_big(
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date );
@@ -458,19 +468,21 @@ static void file_archscan_big(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
#endif /* AR_HSZ_BIG */
-void file_archscan(char *archive, scanback func, void *closure)
+void file_archscan( const char * archive, scanback func, void *closure)
{
int fd;
char fl_magic[SAIAMAG];
- if (( fd = open(archive, O_RDONLY, 0)) < 0)
+ if (( fd = open( archive, O_RDONLY, 0)) < 0)
return;
if (read( fd, fl_magic, SAIAMAG) != SAIAMAG
@@ -480,16 +492,16 @@ void file_archscan(char *archive, scanback func, void *closure)
return;
}
- if (strncmp(AIAMAG, fl_magic, SAIAMAG) == 0)
+ if ( strncmp( AIAMAG, fl_magic, SAIAMAG ) == 0 )
{
/* read small variant */
- file_archscan_small(fd, archive, func, closure);
+ file_archscan_small( fd, archive, func, closure );
}
#ifdef AR_HSZ_BIG
- else if (strncmp(AIAMAGBIG, fl_magic, SAIAMAG) == 0)
+ else if ( strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) == 0 )
{
/* read big variant */
- file_archscan_big(fd, archive, func, closure);
+ file_archscan_big( fd, archive, func, closure );
}
#endif
diff --git a/tools/build/v2/engine/filevms.c b/tools/build/v2/engine/filevms.c
deleted file mode 100644
index d2ab2047f0..0000000000
--- a/tools/build/v2/engine/filevms.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-/*
- * filevms.c - scan directories and libaries on VMS
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split into pathvms.c
- */
-
-# include <rms.h>
-# include <iodef.h>
-# include <ssdef.h>
-# include <string.h>
-# include <stdlib.h>
-# include <stdio.h>
-# include <descrip.h>
-
-#include <lbrdef.h>
-#include <credef.h>
-#include <mhddef.h>
-#include <lhidef.h>
-#include <lib$routines.h>
-#include <starlet.h>
-
-/* Supply missing prototypes for lbr$-routines*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int lbr$set_module(
- void **,
- unsigned long *,
- struct dsc$descriptor_s *,
- unsigned short *,
- void * );
-
-int lbr$open( void **,
- struct dsc$descriptor_s *,
- void *,
- void *,
- void *,
- void *,
- void * );
-
-int lbr$ini_control(
- void **,
- unsigned long *,
- unsigned long *,
- void * );
-
-int lbr$get_index(
- void **,
- unsigned long *,
- int (*func)( struct dsc$descriptor_s *, unsigned long *),
- void * );
-
-int lbr$close(
- void ** );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void
-file_cvttime(
- unsigned int *curtime,
- time_t *unixtime )
-{
- static const size_t divisor = 10000000;
- static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
- int delta[2], remainder;
-
- lib$subx( curtime, bastim, delta );
- lib$ediv( &divisor, delta, unixtime, &remainder );
-}
-
-# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
-
-# define min( a,b ) ((a)<(b)?(a):(b))
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
-
- struct FAB xfab;
- struct NAM xnam;
- struct XABDAT xab;
- char esa[256];
- char filename[256];
- string filename2[1];
- char dirname[256];
- register int status;
- PATHNAME f;
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_root.ptr = dir;
- f.f_root.len = strlen( dir );
-
- /* get the input file specification
- */
- xnam = cc$rms_nam;
- xnam.nam$l_esa = esa;
- xnam.nam$b_ess = sizeof( esa ) - 1;
- xnam.nam$l_rsa = filename;
- xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
-
- xab = cc$rms_xabdat; /* initialize extended attributes */
- xab.xab$b_cod = XAB$C_DAT; /* ask for date */
- xab.xab$l_nxt = NULL; /* terminate XAB chain */
-
- xfab = cc$rms_fab;
- xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
- xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
- xfab.fab$l_fop = FAB$M_NAM;
- xfab.fab$l_fna = dir; /* address of file name */
- xfab.fab$b_fns = strlen( dir ); /* length of file name */
- xfab.fab$l_nam = &xnam; /* address of NAB block */
- xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
-
-
- status = sys$parse( &xfab );
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- if ( !( status & 1 ) )
- return;
-
-
-
- /* Add bogus directory for [000000] */
-
- if ( !strcmp( dir, "[000000]" ) )
- {
- (*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- /* Add bogus directory for [] */
-
- if ( !strcmp( dir, "[]" ) )
- {
- (*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ );
- (*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- string_new( filename2 );
- while ( (status = sys$search( &xfab )) & 1 )
- {
- char *s;
- time_t time;
-
- /* "I think that might work" - eml */
-
- sys$open( &xfab );
- sys$close( &xfab );
-
- file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
-
- filename[xnam.nam$b_rsl] = '\0';
-
- /* What we do with the name depends on the suffix: */
- /* .dir is a directory */
- /* .xxx is a file with a suffix */
- /* . is no suffix at all */
-
- if ( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
- {
- /* directory */
- sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
- f.f_dir.ptr = dirname;
- f.f_dir.len = strlen( dirname );
- f.f_base.ptr = 0;
- f.f_base.len = 0;
- f.f_suffix.ptr = 0;
- f.f_suffix.len = 0;
- }
- else
- {
- /* normal file with a suffix */
- f.f_dir.ptr = 0;
- f.f_dir.len = 0;
- f.f_base.ptr = xnam.nam$l_name;
- f.f_base.len = xnam.nam$b_name;
- f.f_suffix.ptr = xnam.nam$l_type;
- f.f_suffix.len = xnam.nam$b_type;
- }
-
- string_truncate( filename2, 0 );
- path_build( &f, filename2, 0 );
-
- /*
- if ( DEBUG_SEARCH )
- printf("root '%s' base %.*s suf %.*s = %s\n",
- dir,
- xnam.nam$b_name, xnam.nam$l_name,
- xnam.nam$b_type, xnam.nam$l_type,
- filename2 );
- */
-
- (*func)( closure, filename2->value, 1 /* time valid */, time );
- }
- string_free( filename2 );
-}
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This should never be called, as all files are */
- /* timestampped in file_dirscan() and file_archscan() */
- return -1;
-}
-
-static char *VMS_archive = 0;
-static scanback VMS_func;
-static void *VMS_closure;
-static void *context;
-
-static int
-file_archmember(
- struct dsc$descriptor_s *module,
- unsigned long *rfa )
-{
- static struct dsc$descriptor_s bufdsc =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- struct mhddef *mhd;
- char filename[128];
- char buf[ MAXJPATH ];
-
- int status;
- time_t library_date;
-
- register int i;
- register char *p;
-
- bufdsc.dsc$a_pointer = filename;
- bufdsc.dsc$w_length = sizeof( filename );
- status = lbr$set_module( &context, rfa, &bufdsc,
- &bufdsc.dsc$w_length, NULL );
-
- if ( !(status & 1) )
- return ( 1 );
-
- mhd = (struct mhddef *)filename;
-
- file_cvttime( &mhd->mhd$l_datim, &library_date );
-
- for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; ++i, ++p )
- filename[ i ] = *p;
-
- filename[ i ] = '\0';
-
- sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
-
- (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date );
-
- return ( 1 );
-}
-
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
- static struct dsc$descriptor_s library =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- unsigned long lfunc = LBR$C_READ;
- unsigned long typ = LBR$C_TYP_UNK;
- unsigned long index = 1;
-
- register int status;
-
- VMS_archive = archive;
- VMS_func = func;
- VMS_closure = closure;
-
- status = lbr$ini_control( &context, &lfunc, &typ, NULL );
- if ( !( status & 1 ) )
- return;
-
- library.dsc$a_pointer = archive;
- library.dsc$w_length = strlen( archive );
-
- status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
- if ( !( status & 1 ) )
- return;
-
- (void) lbr$get_index( &context, &index, file_archmember, NULL );
-
- (void) lbr$close( &context );
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/frames.c b/tools/build/v2/engine/frames.c
index 84889f09e7..29f7f03cde 100644
--- a/tools/build/v2/engine/frames.c
+++ b/tools/build/v2/engine/frames.c
@@ -13,7 +13,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
void frame_free( FRAME* frame )
diff --git a/tools/build/v2/engine/frames.h b/tools/build/v2/engine/frames.h
index 693d77fa0a..1e2040d14f 100644
--- a/tools/build/v2/engine/frames.h
+++ b/tools/build/v2/engine/frames.h
@@ -7,6 +7,7 @@
#define FRAMES_DWA20011021_H
#include "lists.h"
+#include "object.h"
#include "modules.h"
typedef struct _PARSE PARSE;
@@ -14,13 +15,14 @@ typedef struct frame FRAME;
struct frame
{
- FRAME * prev;
+ FRAME * prev;
/* The nearest enclosing frame for which module->user_module is true. */
- FRAME * prev_user;
- LOL args[ 1 ];
- module_t * module;
- PARSE * procedure;
- char * rulename;
+ FRAME * prev_user;
+ LOL args[ 1 ];
+ module_t * module;
+ OBJECT * file;
+ int line;
+ const char * rulename;
};
diff --git a/tools/build/v2/engine/function.c b/tools/build/v2/engine/function.c
new file mode 100644
index 0000000000..1688eba4e8
--- /dev/null
+++ b/tools/build/v2/engine/function.c
@@ -0,0 +1,4553 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "lists.h"
+#include "pathsys.h"
+#include "mem.h"
+#include "constants.h"
+#include "jam.h"
+#include "frames.h"
+#include "function.h"
+#include "rules.h"
+#include "variable.h"
+#include "compile.h"
+#include "search.h"
+#include "class.h"
+#include "pathsys.h"
+#include "filesys.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+# ifdef OS_CYGWIN
+# include <sys/cygwin.h>
+# include <windows.h>
+# endif
+
+int glob( const char * s, const char * c );
+void backtrace( FRAME * frame );
+void backtrace_line( FRAME * frame );
+
+#define INSTR_PUSH_EMPTY 0
+#define INSTR_PUSH_CONSTANT 1
+#define INSTR_PUSH_ARG 2
+#define INSTR_PUSH_VAR 3
+#define INSTR_PUSH_VAR_FIXED 57
+#define INSTR_PUSH_GROUP 4
+#define INSTR_PUSH_RESULT 5
+#define INSTR_PUSH_APPEND 6
+#define INSTR_SWAP 7
+
+#define INSTR_JUMP_EMPTY 8
+#define INSTR_JUMP_NOT_EMPTY 9
+
+#define INSTR_JUMP 10
+#define INSTR_JUMP_LT 11
+#define INSTR_JUMP_LE 12
+#define INSTR_JUMP_GT 13
+#define INSTR_JUMP_GE 14
+#define INSTR_JUMP_EQ 15
+#define INSTR_JUMP_NE 16
+#define INSTR_JUMP_IN 17
+#define INSTR_JUMP_NOT_IN 18
+
+#define INSTR_JUMP_NOT_GLOB 19
+
+#define INSTR_FOR_INIT 56
+#define INSTR_FOR_LOOP 20
+
+#define INSTR_SET_RESULT 21
+#define INSTR_RETURN 22
+#define INSTR_POP 23
+
+#define INSTR_PUSH_LOCAL 24
+#define INSTR_POP_LOCAL 25
+#define INSTR_SET 26
+#define INSTR_APPEND 27
+#define INSTR_DEFAULT 28
+
+#define INSTR_PUSH_LOCAL_FIXED 58
+#define INSTR_POP_LOCAL_FIXED 59
+#define INSTR_SET_FIXED 60
+#define INSTR_APPEND_FIXED 61
+#define INSTR_DEFAULT_FIXED 62
+
+#define INSTR_PUSH_LOCAL_GROUP 29
+#define INSTR_POP_LOCAL_GROUP 30
+#define INSTR_SET_GROUP 31
+#define INSTR_APPEND_GROUP 32
+#define INSTR_DEFAULT_GROUP 33
+
+#define INSTR_PUSH_ON 34
+#define INSTR_POP_ON 35
+#define INSTR_SET_ON 36
+#define INSTR_APPEND_ON 37
+#define INSTR_DEFAULT_ON 38
+
+#define INSTR_CALL_RULE 39
+
+#define INSTR_APPLY_MODIFIERS 40
+#define INSTR_APPLY_INDEX 41
+#define INSTR_APPLY_INDEX_MODIFIERS 42
+#define INSTR_APPLY_MODIFIERS_GROUP 43
+#define INSTR_APPLY_INDEX_GROUP 44
+#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
+#define INSTR_COMBINE_STRINGS 46
+
+#define INSTR_INCLUDE 47
+#define INSTR_RULE 48
+#define INSTR_ACTIONS 49
+#define INSTR_PUSH_MODULE 50
+#define INSTR_POP_MODULE 51
+#define INSTR_CLASS 52
+#define INSTR_BIND_MODULE_VARIABLES 63
+
+#define INSTR_APPEND_STRINGS 53
+#define INSTR_WRITE_FILE 54
+#define INSTR_OUTPUT_STRINGS 55
+
+typedef struct instruction
+{
+ unsigned int op_code;
+ int arg;
+} instruction;
+
+typedef struct _subfunction
+{
+ OBJECT * name;
+ FUNCTION * code;
+ int local;
+} SUBFUNCTION;
+
+typedef struct _subaction
+{
+ OBJECT * name;
+ FUNCTION * command;
+ int flags;
+} SUBACTION;
+
+#define FUNCTION_BUILTIN 0
+#define FUNCTION_JAM 1
+
+struct argument {
+ int flags;
+#define ARG_ONE 0
+#define ARG_OPTIONAL 1
+#define ARG_PLUS 2
+#define ARG_STAR 3
+#define ARG_VARIADIC 4
+ OBJECT * type_name;
+ OBJECT * arg_name;
+ int index;
+};
+
+struct arg_list {
+ int size;
+ struct argument * args;
+};
+
+struct _function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+ struct arg_list * formal_arguments;
+ int num_formal_arguments;
+};
+
+typedef struct _builtin_function
+{
+ FUNCTION base;
+ LIST * ( * func )( FRAME *, int flags );
+ int flags;
+} BUILTIN_FUNCTION;
+
+typedef struct _jam_function
+{
+ FUNCTION base;
+ int code_size;
+ instruction * code;
+ int num_constants;
+ OBJECT * * constants;
+ int num_subfunctions;
+ SUBFUNCTION * functions;
+ int num_subactions;
+ SUBACTION * actions;
+ FUNCTION * generic;
+ OBJECT * file;
+ int line;
+} JAM_FUNCTION;
+
+
+#ifdef HAVE_PYTHON
+
+#define FUNCTION_PYTHON 2
+
+typedef struct _python_function
+{
+ FUNCTION base;
+ PyObject * python_function;
+} PYTHON_FUNCTION;
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame );
+
+#endif
+
+
+struct _stack
+{
+ void * data;
+};
+
+static void * stack;
+
+STACK * stack_global()
+{
+ static STACK result;
+ if ( !stack )
+ {
+ int size = 1 << 21;
+ stack = BJAM_MALLOC( size );
+ result.data = (char *)stack + size;
+ }
+ return &result;
+}
+
+static void check_alignment( STACK * s )
+{
+ assert( (unsigned long)s->data % sizeof( LIST * ) == 0 );
+}
+
+void * stack_allocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data - size;
+ check_alignment( s );
+ return s->data;
+}
+
+void stack_deallocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data + size;
+ check_alignment( s );
+}
+
+void stack_push( STACK * s, LIST * l )
+{
+ *(LIST * *)stack_allocate( s, sizeof( LIST * ) ) = l;
+}
+
+LIST * stack_pop( STACK * s )
+{
+ LIST * result = *(LIST * *)s->data;
+ stack_deallocate( s, sizeof( LIST * ) );
+ return result;
+}
+
+LIST * stack_top(STACK * s)
+{
+ check_alignment( s );
+ return *(LIST * *)s->data;
+}
+
+LIST * stack_at( STACK * s, int n )
+{
+ check_alignment( s );
+ return *((LIST * *)s->data + n);
+}
+
+void stack_set( STACK * s, int n, LIST * value )
+{
+ check_alignment( s );
+ *((LIST * *)s->data + n) = value;
+}
+
+void * stack_get( STACK * s )
+{
+ check_alignment( s );
+ return (LIST * *)s->data;
+}
+
+LIST * frame_get_local( FRAME * frame, int idx )
+{
+ /* The only local variables are the arguments */
+ return list_copy( lol_get( frame->args, idx ) );
+}
+
+static OBJECT * function_get_constant( JAM_FUNCTION * function, int idx )
+{
+ return function->constants[ idx ];
+}
+
+static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame, int idx )
+{
+ return list_copy( var_get( frame->module, function->constants[idx] ) );
+}
+
+static void function_set_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_SET );
+}
+
+static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ return var_swap( frame->module, function->constants[idx], value );
+}
+
+static void function_append_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_APPEND );
+}
+
+static void function_default_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_DEFAULT );
+}
+
+static void function_set_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBFUNCTION * sub = function->functions + idx;
+ new_rule_body( frame->module, sub->name, sub->code, !sub->local );
+}
+
+static void function_set_actions( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBACTION * sub = function->actions + idx;
+ LIST * bindlist = stack_pop( s );
+
+ new_rule_actions( frame->module, sub->name, sub->command, bindlist, sub->flags );
+}
+
+/*
+ * returns the index if name is "<", ">", "1", "2", ... or "19"
+ * otherwise returns -1.
+ */
+
+static int get_argument_index( const char * s )
+{
+ if( s[ 0 ] != '\0')
+ {
+ if( s[ 1 ] == '\0' )
+ {
+ switch ( s[ 0 ] )
+ {
+ case '<': return 0;
+ case '>': return 1;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 0 ] - '1';
+ }
+ }
+ else if ( s[ 0 ] == '1' && s[ 2 ] == '\0' )
+ {
+ switch( s[ 1 ] )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 1 ] - '0' + 10 - 1;
+ }
+ }
+ }
+ return -1;
+}
+
+static LIST * function_get_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name )
+{
+ int idx = get_argument_index( object_str( name ) );
+ if( idx != -1 )
+ {
+ return list_copy( lol_get( frame->args, idx ) );
+ }
+ else
+ {
+ return list_copy( var_get( frame->module, name ) );
+ }
+}
+
+static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( frame->module, name, value, VAR_SET );
+}
+
+static LIST * function_swap_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ return var_swap( frame->module, name, value );
+}
+
+static void function_append_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( frame->module, name, value, VAR_APPEND );
+}
+
+static void function_default_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ var_set( frame->module, name, value, VAR_DEFAULT );
+}
+
+static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, const char * unexpanded, OBJECT * file, int line )
+{
+ FRAME inner[ 1 ];
+ int i;
+ LIST * first = stack_pop( s );
+ LIST * result = L0;
+ OBJECT * rulename;
+ LIST * trailing;
+
+ frame->file = file;
+ frame->line = line;
+
+ if ( list_empty( first ) )
+ {
+ backtrace_line( frame );
+ printf( "warning: rulename %s expands to empty string\n", unexpanded );
+ backtrace( frame );
+
+ list_free( first );
+
+ for( i = 0; i < n_args; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+
+ return result;
+ }
+
+ rulename = object_copy( list_front( first ) );
+
+ frame_init( inner );
+
+ inner->prev = frame;
+ inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
+
+ for( i = 0; i < n_args; ++i )
+ {
+ lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
+ }
+
+ for( i = 0; i < n_args; ++i )
+ {
+ stack_pop( s );
+ }
+
+ trailing = list_pop_front( first );
+ if ( trailing )
+ {
+ if ( inner->args->count == 0 )
+ {
+ lol_add( inner->args, trailing );
+ }
+ else
+ {
+ LIST * * l = &inner->args->list[0];
+ *l = list_append( trailing, *l );
+ }
+ }
+
+ result = evaluate_rule( rulename, inner );
+ frame_free( inner );
+ object_free( rulename );
+ return result;
+}
+
+/* Variable expansion */
+
+typedef struct
+{
+ int sub1;
+ int sub2;
+} subscript_t;
+
+typedef struct
+{
+ PATHNAME f; /* :GDBSMR -- pieces */
+ char parent; /* :P -- go to parent directory */
+ char filemods; /* one of the above applied */
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char to_slashes; /* :T -- convert "\" to "/" */
+ char to_windows; /* :W -- convert cygwin to native paths */
+ PATHPART empty; /* :E -- default for empties */
+ PATHPART join; /* :J -- join list with char */
+} VAR_EDITS;
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end );
+static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length );
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits );
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits );
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed );
+
+
+/*
+ * var_edit_parse() - parse : modifiers into PATHNAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing or
+ * omitting elements of a filename, and so they are parsed into a PATHNAME
+ * structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with the given value.
+ * Modifiers without the "=value" cause everything but the component X to be
+ * omitted. X is one of:
+ *
+ * G <grist>
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit_file() below and path_build() obligingly follow this convention.
+ */
+
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed )
+{
+ while ( *mods )
+ {
+ PATHPART * fp;
+
+ switch ( *mods++ )
+ {
+ case 'L': edits->downshift = 1; continue;
+ case 'U': edits->upshift = 1; continue;
+ case 'P': edits->parent = edits->filemods = 1; continue;
+ case 'E': fp = &edits->empty; goto strval;
+ case 'J': fp = &edits->join; goto strval;
+ case 'G': fp = &edits->f.f_grist; goto fileval;
+ case 'R': fp = &edits->f.f_root; goto fileval;
+ case 'D': fp = &edits->f.f_dir; goto fileval;
+ case 'B': fp = &edits->f.f_base; goto fileval;
+ case 'S': fp = &edits->f.f_suffix; goto fileval;
+ case 'M': fp = &edits->f.f_member; goto fileval;
+ case 'T': edits->to_slashes = 1; continue;
+ case 'W': edits->to_windows = 1; continue;
+ default:
+ continue; /* Should complain, but so what... */
+ }
+
+ fileval:
+ /* Handle :CHARS, where each char (without a following =) selects a
+ * particular file path element. On the first such char, we deselect all
+ * others (by setting ptr = "", len = 0) and for each char we select
+ * that element (by setting ptr = 0).
+ */
+ edits->filemods = 1;
+
+ if ( *mods != '=' )
+ {
+ if ( !havezeroed++ )
+ {
+ int i;
+ for ( i = 0; i < 6; ++i )
+ {
+ edits->f.part[ i ].len = 0;
+ edits->f.part[ i ].ptr = "";
+ }
+ }
+
+ fp->ptr = 0;
+ continue;
+ }
+
+ strval:
+ /* Handle :X=value, or :X */
+ if ( *mods != '=' )
+ {
+ fp->ptr = "";
+ fp->len = 0;
+ }
+ else
+ {
+ fp->ptr = ++mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+
+ return havezeroed;
+}
+
+/*
+ * var_edit_file() - copy input target name to output, modifying filename.
+ */
+
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits )
+{
+ if ( edits->filemods )
+ {
+ PATHNAME pathname;
+
+ /* Parse apart original filename, putting parts into "pathname". */
+ path_parse( in, &pathname );
+
+ /* Replace any pathname with edits->f */
+ if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
+ if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
+ if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
+ if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
+ if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
+ if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
+
+ /* If requested, modify pathname to point to parent. */
+ if ( edits->parent )
+ path_parent( &pathname );
+
+ /* Put filename back together. */
+ path_build( &pathname, out, 0 );
+ }
+ else
+ {
+ string_append( out, in );
+ }
+}
+
+/*
+ * var_edit_shift() - do upshift/downshift mods.
+ */
+
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+{
+ if ( edits->upshift || edits->downshift || edits->to_windows || edits->to_slashes )
+ {
+ /* Handle upshifting, downshifting and slash translation now. */
+ char * p;
+# ifdef OS_CYGWIN
+ if ( edits->to_windows )
+ {
+ /* FIXME: skip grist */
+ char result[ MAX_PATH + 1 ];
+ cygwin_conv_to_win32_path( out->value + pos, result );
+ assert( strlen( result ) <= MAX_PATH );
+ string_truncate( out, pos );
+ string_append( out, result );
+ edits->to_slashes = 0;
+ }
+# endif
+ for ( p = out->value + pos; *p; ++p)
+ {
+ if ( edits->upshift )
+ *p = toupper( *p );
+ else if ( edits->downshift )
+ *p = tolower( *p );
+ if ( edits->to_slashes && ( *p == '\\' ) )
+ *p = '/';
+ }
+ }
+}
+
+/*
+ * Reads n LISTs from the top of the STACK and
+ * combines them to form VAR_EDITS.
+ *
+ * returns the number of VAR_EDITS pushed onto
+ * the STACK.
+ */
+
+static int expand_modifiers( STACK * s, int n )
+{
+ int i;
+ int total = 1;
+ LIST * * args = stack_get( s );
+ for( i = 0; i < n; ++i)
+ total *= list_length( args[i] );
+
+ if ( total != 0 )
+ {
+ VAR_EDITS * out = stack_allocate( s, total * sizeof(VAR_EDITS) );
+ LISTITER * iter = stack_allocate( s, n * sizeof(LIST *) );
+ for (i = 0; i < n; ++i )
+ {
+ iter[i] = list_begin( args[i] );
+ }
+ i = 0;
+ {
+ int havezeroed;
+ loop:
+ memset( out, 0, sizeof( *out ) );
+ havezeroed = 0;
+ for (i = 0; i < n; ++i )
+ {
+ havezeroed = var_edit_parse( object_str( list_item( iter[i] ) ), out, havezeroed );
+ }
+ ++out;
+ while ( --i >= 0 )
+ {
+ if ( list_next( iter[i] ) != list_end( args[i] ) )
+ {
+ iter[i] = list_next( iter[i] );
+ goto loop;
+ }
+ else
+ {
+ iter[i] = list_begin( args[i] );
+ }
+ }
+ }
+ stack_deallocate( s, n * sizeof( LIST * ) );
+ }
+ return total;
+}
+
+static LIST * apply_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
+ string buf[1];
+ string_new( buf );
+ result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ), list_end( value ) );
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Parse a string of the form "1-2", "-2--1", "2-"
+ * and return the two subscripts.
+ */
+
+subscript_t parse_subscript( const char * s )
+{
+ subscript_t result;
+ result.sub1 = 0;
+ result.sub2 = 0;
+ do /* so we can use "break" */
+ {
+ /* Allow negative subscripts. */
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+ result.sub1 = atoi( s );
+
+ /* Skip over the first symbol, which is either a digit or dash. */
+ ++s;
+ while ( isdigit( *s ) ) ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = result.sub1;
+ break;
+ }
+
+ if ( *s != '-' )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = -1;
+ break;
+ }
+
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ /* First, compute the index of the last element. */
+ result.sub2 = atoi( s );
+ while ( isdigit( *++s ) );
+
+ if ( *s != '\0' )
+ result.sub2 = 0;
+
+ } while ( 0 );
+ return result;
+}
+
+static LIST * apply_subscript( STACK * s )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ int length = list_length( value );
+ string buf[1];
+ LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ string_new( buf );
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ {
+ LISTITER iter = list_begin( value );
+ LISTITER end = list_end( value );
+ subscript_t subscript = parse_subscript( object_str( list_item( indices_iter ) ) );
+ get_iters( subscript, &iter, &end, length );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Reads the LIST from first and applies subscript to it.
+ * The results are written to *first and *last.
+ */
+
+static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length )
+{
+ int start;
+ int size;
+ LISTITER iter;
+ LISTITER end;
+ {
+
+ if ( subscript.sub1 < 0 )
+ start = length + subscript.sub1;
+ else if( subscript.sub1 > length )
+ start = length;
+ else
+ start = subscript.sub1 - 1;
+
+ if ( subscript.sub2 < 0 )
+ size = length + 1 + subscript.sub2 - start;
+ else
+ size = subscript.sub2 - start;
+
+ /*
+ * HACK: When the first subscript is before the start of the
+ * list, it magically becomes the beginning of the list.
+ * This is inconsistent, but needed for backwards
+ * compatibility.
+ */
+ if ( start < 0 )
+ start = 0;
+
+ /* The "sub2 < 0" test handles the semantic error of sub2 <
+ * sub1.
+ */
+ if ( size < 0 )
+ size = 0;
+
+ if ( start + size > length )
+ size = length - start;
+ }
+
+ iter = *first;
+ while ( start-- > 0 )
+ iter = list_next( iter );
+
+ end = iter;
+ while ( size-- > 0 )
+ end = list_next( end );
+
+ *first = iter;
+ *last = end;
+}
+
+static LIST * apply_modifiers_empty( LIST * result, string * buf, VAR_EDITS * edits, int n)
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].empty.ptr )
+ {
+ /** FIXME: is empty.ptr always null-terminated? */
+ var_edit_file( edits[i].empty.ptr, buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_non_empty( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER begin, LISTITER end )
+{
+ int i;
+ LISTITER iter;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].join.ptr )
+ {
+ var_edit_file( object_str( list_item( begin ) ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ for ( iter = list_next( begin ); iter != end; iter = list_next( iter ) )
+ {
+ size_t size;
+ string_append( buf, edits[i].join.ptr );
+ size = buf->size;
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_shift( buf, size, edits + i );
+ }
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ else
+ {
+ for ( iter = begin; iter != end; iter = list_next( iter ) )
+ {
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end )
+{
+ if ( iter != end )
+ {
+ return apply_modifiers_non_empty( result, buf, edits, n, iter, end );
+ }
+ else
+ {
+ return apply_modifiers_empty( result, buf, edits, n );
+ }
+}
+
+static LIST * apply_subscript_and_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
+ int length = list_length( value );
+ string buf[1];
+ LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ string_new( buf );
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ {
+ LISTITER iter = list_begin( value );
+ LISTITER end = list_end( value );
+ subscript_t sub = parse_subscript( object_str( list_item( indices_iter ) ) );
+ get_iters( sub, &iter, &end, length );
+ result = apply_modifiers_impl( result, buf, edits, n, iter, end );
+ }
+ string_free( buf );
+ return result;
+}
+
+typedef struct expansion_item
+{
+ LISTITER elem;
+ LIST * saved;
+ int size;
+} expansion_item;
+
+static LIST * expand( expansion_item * elem, int length )
+{
+ LIST * result = L0;
+ string buf[1];
+ int size = 0;
+ int i;
+ assert( length > 0 );
+ for ( i = 0; i < length; ++i )
+ {
+ int max = 0;
+ LISTITER iter = elem[i].elem, end = list_end( elem[i].saved );
+ if ( iter == end ) return result;
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ int len = strlen( object_str( list_item( iter ) ) );
+ if ( len > max ) max = len;
+ }
+ size += max;
+ }
+ string_new( buf );
+ string_reserve( buf, size );
+ i = 0;
+ {
+ loop:
+ for ( ; i < length; ++i )
+ {
+ elem[i].size = buf->size;
+ string_append( buf, object_str( list_item( elem[i].elem ) ) );
+ }
+ result = list_push_back( result, object_new( buf->value ) );
+ while ( --i >= 0 )
+ {
+ if( list_next( elem[i].elem ) != list_end( elem[i].saved ) )
+ {
+ elem[i].elem = list_next( elem[i].elem );
+ string_truncate( buf, elem[i].size );
+ goto loop;
+ }
+ else
+ {
+ elem[i].elem = list_begin( elem[i].saved );
+ }
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+static void combine_strings( STACK * s, int n, string * out )
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ LIST * values = stack_pop( s );
+ LISTITER iter = list_begin( values ), end = list_end( values );
+ if ( iter != end )
+ {
+ string_append( out, object_str( list_item( iter ) ) );
+ for ( iter = list_next( iter ); iter != end; iter = list_next( iter ) )
+ {
+ string_push_back( out, ' ' );
+ string_append( out, object_str( list_item( iter ) ) );
+ }
+ list_free( values );
+ }
+ }
+}
+
+struct dynamic_array
+{
+ int size;
+ int capacity;
+ void * data;
+};
+
+static void dynamic_array_init( struct dynamic_array * array )
+{
+ array->size = 0;
+ array->capacity = 0;
+ array->data = 0;
+}
+
+static void dynamic_array_free( struct dynamic_array * array )
+{
+ BJAM_FREE( array->data );
+}
+
+static void dynamic_array_push_impl( struct dynamic_array * array, void * value, int unit_size )
+{
+ if ( array->capacity == 0 )
+ {
+ array->capacity = 2;
+ array->data = BJAM_MALLOC( array->capacity * unit_size );
+ }
+ else if ( array->capacity == array->size )
+ {
+ void * new_data;
+ array->capacity *= 2;
+ new_data = BJAM_MALLOC( array->capacity * unit_size );
+ memcpy( new_data, array->data, array->size * unit_size );
+ BJAM_FREE( array->data );
+ array->data = new_data;
+ }
+ memcpy( (char *)array->data + array->size * unit_size, value, unit_size );
+ ++array->size;
+}
+
+#define dynamic_array_push( array, value ) ( dynamic_array_push_impl( array, &value, sizeof(value) ) )
+#define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx])
+
+/*
+ * struct compiler
+ */
+
+struct label_info
+{
+ int absolute_position;
+ struct dynamic_array uses[1];
+};
+
+struct stored_rule
+{
+ OBJECT * name;
+ PARSE * parse;
+ int num_arguments;
+ struct arg_list * arguments;
+ int local;
+};
+
+typedef struct compiler
+{
+ struct dynamic_array code[1];
+ struct dynamic_array constants[1];
+ struct dynamic_array labels[1];
+ struct dynamic_array rules[1];
+ struct dynamic_array actions[1];
+} compiler;
+
+static void compiler_init( compiler * c )
+{
+ dynamic_array_init( c->code );
+ dynamic_array_init( c->constants );
+ dynamic_array_init( c->labels );
+ dynamic_array_init( c->rules );
+ dynamic_array_init( c->actions );
+}
+
+static void compiler_free( compiler * c )
+{
+ int i;
+ dynamic_array_free( c->actions );
+ dynamic_array_free( c->rules );
+ for ( i = 0; i < c->labels->size; ++i )
+ {
+ dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i ).uses );
+ }
+ dynamic_array_free( c->labels );
+ dynamic_array_free( c->constants );
+ dynamic_array_free( c->code );
+}
+
+static void compile_emit_instruction( compiler * c, instruction instr )
+{
+ dynamic_array_push( c->code, instr );
+}
+
+static int compile_new_label( compiler * c )
+{
+ int result = c->labels->size;
+ struct label_info info;
+ info.absolute_position = -1;
+ dynamic_array_init( info.uses );
+ dynamic_array_push( c->labels, info );
+ return result;
+}
+
+static void compile_set_label( compiler * c, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ int i;
+ assert( l->absolute_position == -1 );
+ l->absolute_position = pos;
+ for ( i = 0; i < l->uses->size; ++i )
+ {
+ int id = dynamic_array_at( int, l->uses, i );
+ int offset = (int)(pos - id - 1);
+ dynamic_array_at( instruction, c->code, id ).arg = offset;
+ }
+}
+
+static void compile_emit( compiler * c, unsigned int op_code, int arg )
+{
+ instruction instr;
+ instr.op_code = op_code;
+ instr.arg = arg;
+ compile_emit_instruction( c, instr );
+}
+
+static void compile_emit_branch( compiler * c, unsigned int op_code, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ instruction instr;
+ instr.op_code = op_code;
+ if ( l->absolute_position == -1 )
+ {
+ instr.arg = 0;
+ dynamic_array_push( l->uses, pos );
+ }
+ else
+ {
+ instr.arg = (int)( l->absolute_position - pos - 1 );
+ }
+ compile_emit_instruction( c, instr );
+}
+
+static int compile_emit_constant( compiler * c, OBJECT * value )
+{
+ OBJECT * copy = object_copy( value );
+ dynamic_array_push( c->constants, copy );
+ return c->constants->size - 1;
+}
+
+static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse, int num_arguments, struct arg_list * arguments, int local )
+{
+ struct stored_rule rule;
+ rule.name = object_copy( name );
+ rule.parse = parse;
+ rule.num_arguments = num_arguments;
+ rule.arguments = arguments;
+ rule.local = local;
+ dynamic_array_push( c->rules, rule );
+ return (int)( c->rules->size - 1 );
+}
+
+static int compile_emit_actions( compiler * c, PARSE * parse )
+{
+ SUBACTION a;
+ a.name = object_copy( parse->string );
+ a.command = function_compile_actions( object_str( parse->string1 ), parse->file, parse->line );
+ a.flags = parse->num;
+ dynamic_array_push( c->actions, a );
+ return (int)( c->actions->size - 1 );
+}
+
+static JAM_FUNCTION * compile_to_function( compiler * c )
+{
+ JAM_FUNCTION * result = BJAM_MALLOC( sizeof(JAM_FUNCTION) );
+ int i;
+ result->base.type = FUNCTION_JAM;
+ result->base.reference_count = 1;
+ result->base.formal_arguments = 0;
+ result->base.num_formal_arguments = 0;
+
+ result->base.rulename = 0;
+
+ result->code_size = c->code->size;
+ result->code = BJAM_MALLOC( c->code->size * sizeof(instruction) );
+ memcpy( result->code, c->code->data, c->code->size * sizeof(instruction) );
+
+ result->constants = BJAM_MALLOC( c->constants->size * sizeof(OBJECT *) );
+ memcpy( result->constants, c->constants->data, c->constants->size * sizeof(OBJECT *) );
+ result->num_constants = c->constants->size;
+
+ result->num_subfunctions = c->rules->size;
+ result->functions = BJAM_MALLOC( c->rules->size * sizeof(SUBFUNCTION) );
+ for ( i = 0; i < c->rules->size; ++i )
+ {
+ struct stored_rule * rule = &dynamic_array_at( struct stored_rule, c->rules, i );
+ result->functions[i].name = rule->name;
+ result->functions[i].code = function_compile( rule->parse );
+ result->functions[i].code->num_formal_arguments = rule->num_arguments;
+ result->functions[i].code->formal_arguments = rule->arguments;
+ result->functions[i].local = rule->local;
+ }
+
+ result->actions = BJAM_MALLOC( c->actions->size * sizeof(SUBACTION) );
+ memcpy( result->actions, c->actions->data, c->actions->size * sizeof(SUBACTION) );
+ result->num_subactions = c->actions->size;
+
+ result->generic = 0;
+
+ result->file = 0;
+ result->line = -1;
+
+ return result;
+}
+
+/*
+ * Parsing of variable expansions
+ */
+
+typedef struct VAR_PARSE_GROUP
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_GROUP;
+
+typedef struct VAR_PARSE_ACTIONS
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_ACTIONS;
+
+#define VAR_PARSE_TYPE_VAR 0
+#define VAR_PARSE_TYPE_STRING 1
+#define VAR_PARSE_TYPE_FILE 2
+
+typedef struct _var_parse
+{
+ int type; /* string or variable */
+} VAR_PARSE;
+
+typedef struct
+{
+ VAR_PARSE base;
+ VAR_PARSE_GROUP * name;
+ VAR_PARSE_GROUP * subscript;
+ struct dynamic_array modifiers[1];
+} VAR_PARSE_VAR;
+
+typedef struct
+{
+ VAR_PARSE base;
+ OBJECT * s;
+} VAR_PARSE_STRING;
+
+typedef struct
+{
+ VAR_PARSE base;
+ struct dynamic_array filename[1];
+ struct dynamic_array contents[1];
+} VAR_PARSE_FILE;
+
+static void var_parse_free( VAR_PARSE * );
+
+/*
+ * VAR_PARSE_GROUP
+ */
+
+static VAR_PARSE_GROUP * var_parse_group_new()
+{
+ VAR_PARSE_GROUP * result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_group_free( VAR_PARSE_GROUP * group )
+{
+ int i;
+ for ( i = 0; i < group->elems->size; ++i )
+ {
+ var_parse_free( dynamic_array_at( VAR_PARSE *, group->elems, i ) );
+ }
+ dynamic_array_free( group->elems );
+ BJAM_FREE( group );
+}
+
+static void var_parse_group_add( VAR_PARSE_GROUP * group, VAR_PARSE * elem )
+{
+ dynamic_array_push( group->elems, elem );
+}
+
+static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group, const char * start, const char * end )
+{
+ if ( start != end )
+ {
+ string buf[1];
+ VAR_PARSE_STRING * value = (VAR_PARSE_STRING *)BJAM_MALLOC( sizeof(VAR_PARSE_STRING) );
+ value->base.type = VAR_PARSE_TYPE_STRING;
+ string_new( buf );
+ string_append_range( buf, start, end );
+ value->s = object_new( buf->value );
+ string_free( buf );
+ var_parse_group_add( group, (VAR_PARSE *)value );
+ }
+}
+
+VAR_PARSE_STRING * var_parse_group_as_literal( VAR_PARSE_GROUP * group )
+{
+ if ( group->elems->size == 1 )
+ {
+ VAR_PARSE * result = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
+ if ( result->type == VAR_PARSE_TYPE_STRING )
+ {
+ return (VAR_PARSE_STRING *)result;
+ }
+ }
+ return 0;
+}
+
+/*
+ * VAR_PARSE_ACTIONS
+ */
+
+static VAR_PARSE_ACTIONS * var_parse_actions_new()
+{
+ VAR_PARSE_ACTIONS * result = (VAR_PARSE_ACTIONS *)BJAM_MALLOC( sizeof(VAR_PARSE_ACTIONS) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_actions_free( VAR_PARSE_ACTIONS * actions )
+{
+ int i;
+ for ( i = 0; i < actions->elems->size; ++i )
+ {
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, i ) );
+ }
+ dynamic_array_free( actions->elems );
+ BJAM_FREE( actions );
+}
+
+/*
+ * VAR_PARSE_VAR
+ */
+
+static VAR_PARSE_VAR * var_parse_var_new()
+{
+ VAR_PARSE_VAR * result = BJAM_MALLOC( sizeof( VAR_PARSE_VAR ) );
+ result->base.type = VAR_PARSE_TYPE_VAR;
+ result->name = var_parse_group_new();
+ result->subscript = 0;
+ dynamic_array_init( result->modifiers );
+ return result;
+}
+
+static void var_parse_var_free( VAR_PARSE_VAR * var )
+{
+ int i;
+ var_parse_group_free( var->name );
+ if ( var->subscript )
+ var_parse_group_free( var->subscript );
+ for( i = 0; i < var->modifiers->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, var->modifiers, i ) );
+ dynamic_array_free( var->modifiers );
+ BJAM_FREE( var );
+}
+
+static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ dynamic_array_push( var->modifiers, result );
+ return result;
+}
+
+/*
+ * VAR_PARSE_STRING
+ */
+
+static void var_parse_string_free( VAR_PARSE_STRING * string )
+{
+ object_free( string->s );
+ BJAM_FREE( string );
+}
+
+/*
+ * VAR_PARSE_FILE
+ */
+
+static VAR_PARSE_FILE * var_parse_file_new( void )
+{
+ VAR_PARSE_FILE * result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof( VAR_PARSE_FILE ) );
+ result->base.type = VAR_PARSE_TYPE_FILE;
+ dynamic_array_init( result->filename );
+ dynamic_array_init( result->contents );
+ return result;
+}
+
+static void var_parse_file_free( VAR_PARSE_FILE * file )
+{
+ int i;
+ for( i = 0; i < file->filename->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->filename, i ) );
+ dynamic_array_free( file->filename );
+ for( i = 0; i < file->contents->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->contents, i ) );
+ dynamic_array_free( file->contents );
+ BJAM_FREE( file );
+}
+
+/*
+ * VAR_PARSE
+ */
+
+static void var_parse_free( VAR_PARSE * parse )
+{
+ if ( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_free( (VAR_PARSE_VAR *)parse );
+ }
+ else if ( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_free( (VAR_PARSE_STRING *)parse );
+ }
+ else if ( parse->type == VAR_PARSE_TYPE_FILE )
+ {
+ var_parse_file_free( (VAR_PARSE_FILE *)parse );
+ }
+ else
+ {
+ assert(!"Invalid type");
+ }
+}
+
+/*
+ * Compile VAR_PARSE
+ */
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c );
+
+static void var_parse_var_compile( const VAR_PARSE_VAR * parse, compiler * c )
+{
+ int expand_name = 0;
+ /* If there are modifiers, emit them in reverse order. */
+ if ( parse->modifiers->size > 0 )
+ {
+ int i;
+ for ( i = 0; i < parse->modifiers->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, parse->modifiers->size - i - 1 ), c );
+ }
+ }
+
+ /* If there's a subscript, emit it. */
+ if ( parse->subscript )
+ {
+ var_parse_group_compile( parse->subscript, c );
+ }
+
+ /* If the variable name is empty, look it up. */
+ if ( parse->name->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If the variable name doesn't need to be expanded, look it up. */
+ else if ( parse->name->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ OBJECT * name = ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 ) )->s;
+ int idx = get_argument_index( object_str( name ) );
+ if ( idx != -1 )
+ {
+ compile_emit( c, INSTR_PUSH_ARG, idx );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, name ) );
+ }
+ }
+ /* Otherwise, push the var names and use the group instruction. */
+ else
+ {
+ var_parse_group_compile( parse->name, c );
+ expand_name = 1;
+ }
+
+ /** Select the instruction for expanding the variable. */
+ if ( !parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ /* Nothing to do */
+ }
+ else if ( !parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_PUSH_GROUP, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
+ }
+ if ( parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+}
+
+static void var_parse_string_compile( const VAR_PARSE_STRING * parse, compiler * c )
+{
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s ) );
+}
+
+static void var_parse_file_compile( const VAR_PARSE_FILE * parse, compiler * c )
+{
+ int i;
+ for ( i = 0; i < parse->filename->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->filename, parse->filename->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_APPEND_STRINGS, parse->filename->size );
+ for ( i = 0; i < parse->contents->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->contents, parse->contents->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_WRITE_FILE, parse->contents->size );
+}
+
+static void var_parse_compile( const VAR_PARSE * parse, compiler * c )
+{
+ if( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_compile( (const VAR_PARSE_VAR *)parse, c );
+ }
+ else if( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_compile( (const VAR_PARSE_STRING *)parse, c );
+ }
+ else if( parse->type == VAR_PARSE_TYPE_FILE )
+ {
+ var_parse_file_compile( (const VAR_PARSE_FILE *)parse, c );
+ }
+ else
+ {
+ assert( !"Unknown var parse type." );
+ }
+}
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c )
+{
+ /* Emit the elements in reverse order. */
+ int i;
+ for( i = 0; i < parse->elems->size; ++i)
+ {
+ var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems, parse->elems->size - i - 1 ), c );
+ }
+ /* If there're no elements, emit an empty string. */
+ if ( parse->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If there's more than one element, combine them. */
+ if ( parse->elems->size > 1 )
+ {
+ compile_emit( c, INSTR_COMBINE_STRINGS, parse->elems->size );
+ }
+}
+
+static void var_parse_actions_compile( const VAR_PARSE_ACTIONS * actions, compiler * c )
+{
+ int i;
+ for ( i = 0; i < actions->elems->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, actions->elems->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_OUTPUT_STRINGS, actions->elems->size );
+}
+
+/*
+ * Parse VAR_PARSE_VAR
+ */
+
+static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end );
+static VAR_PARSE * parse_variable( const char * * string );
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+static void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+static void parse_var_string( const char * first, const char * last, struct dynamic_array * out );
+
+/*
+ * Parses a string that can contain variables to expand.
+ */
+
+static VAR_PARSE_GROUP * parse_expansion( const char * * string )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ const char * s = *string;
+ for (;;)
+ {
+ if(try_parse_variable( &s, string, result )) {}
+ else if(s[0] == '\0')
+ {
+ var_parse_group_maybe_add_constant( result, *string, s );
+ return result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+static VAR_PARSE_ACTIONS * parse_actions( const char * string )
+{
+ VAR_PARSE_ACTIONS * result = var_parse_actions_new();
+ parse_var_string( string, string + strlen( string ), result->elems );
+ return result;
+}
+
+/*
+ * Checks whether the string a *s_ starts with
+ * a variable expansion "$(". *string should point
+ * to the first unemitted character before *s.
+ * If *s_ starts with variable expansion, appends
+ * elements to out up to the closing ")", and
+ * adjusts *s_ and *string to point to next character.
+ * Returns 1 if s_ starts with a variable, 0 otherwise.
+ */
+
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ const char * s = *s_;
+ if(s[0] == '$' && s[1] == '(')
+ {
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ var_parse_group_add( out, parse_variable( &s ) );
+ *string = s;
+ *s_ = s;
+ return 1;
+ }
+ else if(s[0] == '@' && s[1] == '(')
+ {
+ int depth = 1;
+ const char * ine;
+ const char * split = 0;
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ ine = s;
+
+ /* Scan the content of the response file @() section. */
+ while ( *ine && ( depth > 0 ) )
+ {
+ switch ( *ine )
+ {
+ case '(': ++depth; break;
+ case ')': --depth; break;
+ case ':':
+ if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
+ split = ine;
+ break;
+ }
+ ++ine;
+ }
+
+ if ( !split || depth != 0 )
+ {
+ return 0;
+ }
+
+ var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) );
+ *string = ine;
+ *s_ = ine;
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static const char * current_file = "";
+static int current_line;
+
+static void parse_error( const char * message )
+{
+ printf( "%s:%d: %s\n", current_file, current_line, message );
+}
+
+/*
+ * Parses a single variable up to the closing ")" and
+ * adjusts *string to point to the next character. *string
+ * should point to the character immediately after
+ * the initial "$("
+ */
+
+static VAR_PARSE * parse_variable( const char * * string )
+{
+ VAR_PARSE_VAR * result = var_parse_var_new();
+ VAR_PARSE_GROUP * name = result->name;
+ const char * s = *string;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, name ) ) {}
+ else if ( s[0] == ':' )
+ {
+ VAR_PARSE_GROUP * mod;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, mod ) ) {}
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, mod );
+ }
+ else if ( s[0] == ':' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ }
+ else if ( s[0] == '[' )
+ {
+ parse_error("unexpected subscript");
+ ++s;
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == '[' )
+ {
+ VAR_PARSE_GROUP * subscript = var_parse_group_new();
+ result->subscript = subscript;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, subscript ) ) {}
+ else if ( s[0] == ']' )
+ {
+ var_parse_group_maybe_add_constant( subscript, *string, s );
+ ++s;
+ *string = s;
+ if ( s[0] == ')' || s[0] == ':' || s[0] == '\0')
+ {
+ break;
+ }
+ else
+ {
+ parse_error( "unexpected text following []" );
+ break;
+ }
+ }
+ else if ( isdigit( s[0] ) || s[0] == '-' )
+ {
+ ++s;
+ }
+ else if( s[0] == '\0' )
+ {
+ parse_error( "malformed subscript" );
+ break;
+ }
+ else
+ {
+ parse_error( "malformed subscript" );
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, name );
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( name, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+static void parse_var_string( const char * first, const char * last, struct dynamic_array * out )
+{
+ const char * saved = first;
+ for ( ; ; )
+ {
+ /* Handle whitespace */
+ for ( ; first != last; ++first ) if ( !isspace(*first) ) break;
+ if ( saved != first )
+ {
+ VAR_PARSE_GROUP * group = var_parse_group_new();
+ var_parse_group_maybe_add_constant( group, saved, first );
+ saved = first;
+ dynamic_array_push( out, group );
+ }
+
+ if ( first == last ) break;
+
+ /* Handle non-whitespace */
+
+ {
+ VAR_PARSE_GROUP * group = var_parse_group_new();
+ for ( ; ; )
+ {
+
+ if( first == last || isspace( *first ) )
+ {
+ var_parse_group_maybe_add_constant( group, saved, first );
+ saved = first;
+ break;
+ }
+ else if ( try_parse_variable( &first, &saved, group ) )
+ {
+ assert( first <= last );
+ }
+ else
+ {
+ ++first;
+ }
+ }
+ dynamic_array_push( out, group );
+ }
+ if ( first == last ) break;
+ }
+}
+
+/*
+ * start should point to the character immediately following the
+ * opening "@(", mid should point to the ":E=", and end should
+ * point to the closing ")".
+ */
+
+static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end )
+{
+ VAR_PARSE_FILE * result = var_parse_file_new();
+ parse_var_string( start, mid, result->filename );
+ parse_var_string( mid + 3, end, result->contents );
+ return (VAR_PARSE *)result;
+}
+
+/*
+ * Given that *s_ points to the character after a "(",
+ * parses up to the matching ")". *string should
+ * point to the first unemitted character before *s_.
+ *
+ * When the function returns, *s_ will point to the character
+ * after the ")", and *string will point to the first
+ * unemitted character before *s_. The range from *string
+ * to *s_ does not contain any variables that need to be
+ * expanded.
+ */
+
+void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ int depth = 1;
+ const char * s = *s_;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, out ) ) { }
+ else if(s[0] == ':' || s[0] == '[')
+ {
+ parse_error( "unbalanced parentheses" );
+ ++s;
+ }
+ else if(s[0] == '\0')
+ {
+ parse_error( "unbalanced parentheses" );
+ break;
+ }
+ else if(s[0] == ')')
+ {
+ ++s;
+ if(--depth == 0) break;
+ }
+ else if(s[0] == '(')
+ {
+ ++depth;
+ ++s;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ *s_ = s;
+}
+
+/*
+ * Main compile
+ */
+
+#define RESULT_STACK 0
+#define RESULT_RETURN 1
+#define RESULT_NONE 2
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location );
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments );
+
+static void compile_condition( PARSE * parse, compiler * c, int branch_true, int label )
+{
+ assert( parse->type == PARSE_EVAL );
+ switch ( parse->num )
+ {
+ case EXPR_EXISTS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NOT_EMPTY, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EMPTY, label );
+ break;
+ }
+ case EXPR_EQUALS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ break;
+ }
+ case EXPR_NOTEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ break;
+ }
+ case EXPR_LESS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ break;
+ }
+ case EXPR_LESSEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ break;
+ }
+ case EXPR_MORE:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ break;
+ }
+ case EXPR_MOREEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ break;
+ }
+ case EXPR_IN:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_IN, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
+ break;
+ }
+ case EXPR_AND:
+ {
+ if ( branch_true )
+ {
+ int f = compile_new_label( c );
+ compile_condition( parse->left, c, 0, f );
+ compile_condition( parse->right, c, 1, label );
+ compile_set_label( c, f );
+ }
+ else
+ {
+ compile_condition( parse->left, c, 0, label );
+ compile_condition( parse->right, c, 0, label );
+ }
+ break;
+ }
+ case EXPR_OR:
+ {
+ if ( branch_true )
+ {
+ compile_condition( parse->left, c, 1, label );
+ compile_condition( parse->right, c, 1, label );
+ }
+ else
+ {
+ int t = compile_new_label( c );
+ compile_condition( parse->left, c, 1, t );
+ compile_condition( parse->right, c, 0, label );
+ compile_set_label( c, t );
+ }
+ break;
+ }
+ case EXPR_NOT:
+ {
+ compile_condition( parse->left, c, !branch_true, label );
+ break;
+ }
+ }
+}
+
+static void adjust_result( compiler * c, int actual_location, int desired_location )
+{
+ if ( actual_location == desired_location )
+ ;
+ else if ( actual_location == RESULT_STACK && desired_location == RESULT_RETURN )
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ else if( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
+ compile_emit( c, INSTR_POP, 0 );
+ else if( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_RESULT, 0 );
+ else if ( actual_location == RESULT_RETURN && desired_location == RESULT_NONE )
+ ;
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_RETURN )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ }
+ else
+ {
+ assert( !"invalid result location" );
+ }
+}
+
+static const char * parse_type( PARSE * parse )
+{
+ switch ( parse->type )
+ {
+ case PARSE_APPEND: return "append";
+ case PARSE_EVAL: return "eval";
+ case PARSE_RULES: return "rules";
+ default: return "unknown";
+ }
+}
+
+static void compile_append_chain( PARSE * parse, compiler * c )
+{
+ assert( parse->type == PARSE_APPEND );
+ if ( parse->left->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_STACK );
+ }
+ else
+ {
+ if ( parse->left->type == PARSE_APPEND )
+ compile_append_chain( parse->left, c );
+ else
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_APPEND, 0 );
+ }
+}
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ compile_append_chain( parse, c );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_EVAL )
+ {
+ /* FIXME: This is only needed because of the bizarre parsing of conditions. */
+ if ( parse->num == EXPR_EXISTS )
+ {
+ compile_parse( parse->left, c, result_location );
+ }
+ else
+ {
+ int f = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ printf( "%s:%d: Conditional used as list (check operator precedence).\n", object_str(parse->file), parse->line );
+
+ /* Emit the condition */
+ compile_condition( parse, c, 0, f );
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_true ) );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ }
+ else if ( parse->type == PARSE_FOREACH )
+ {
+ int var = compile_emit_constant( c, parse->string );
+ int top = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ /*
+ * Evaluate the list.
+ */
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ /* Localize the loop variable */
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_PUSH_LOCAL, var );
+ compile_emit( c, INSTR_SWAP, 1 );
+ }
+
+ compile_emit( c, INSTR_FOR_INIT, 0 );
+ compile_set_label( c, top );
+ compile_emit_branch( c, INSTR_FOR_LOOP, end );
+ compile_emit( c, INSTR_SET, var );
+ compile_emit( c, INSTR_POP, 0 );
+
+ /* Run the loop body */
+ compile_parse( parse->right, c, RESULT_NONE );
+
+ compile_emit_branch( c, INSTR_JUMP, top );
+ compile_set_label( c, end );
+
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_POP_LOCAL, var );
+ }
+
+ adjust_result( c, RESULT_NONE, result_location);
+ }
+ else if( parse->type == PARSE_IF )
+ {
+ int f = compile_new_label( c );
+ /* Emit the condition */
+ compile_condition( parse->left, c, 0, f );
+ /* Emit the if block */
+ compile_parse( parse->right, c, result_location );
+ if ( parse->third->type != PARSE_NULL || result_location != RESULT_NONE )
+ {
+ /* Emit the else block */
+ int end = compile_new_label( c );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_parse( parse->third, c, result_location );
+ compile_set_label( c, end );
+ }
+ else
+ {
+ compile_set_label( c, f );
+ }
+
+ }
+ else if( parse->type == PARSE_WHILE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int test = compile_new_label( c );
+ int top = compile_new_label( c );
+ /* Make sure that we return an empty list if the loop runs zero times. */
+ adjust_result( c, RESULT_NONE, nested_result );
+ /* Jump to the loop test */
+ compile_emit_branch( c, INSTR_JUMP, test );
+ compile_set_label( c, top );
+ /* Emit the loop body */
+ compile_parse( parse->right, c, nested_result );
+ /* Emit the condition */
+ compile_set_label( c, test );
+ compile_condition( parse->left, c, 1, top );
+
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_INCLUDE )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_INCLUDE, 0 );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_MODULE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_MODULE, 0 );
+ compile_parse( parse->right, c, nested_result );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_CLASS )
+ {
+ /* Evaluate the class name. */
+ compile_parse( parse->left->right, c, RESULT_STACK );
+ /* Evaluate the base classes. */
+ if ( parse->left->left )
+ {
+ compile_parse( parse->left->left->right, c, RESULT_STACK );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ }
+ compile_emit( c, INSTR_CLASS, 0 );
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_LIST )
+ {
+ OBJECT * o = parse->string;
+ const char * s = object_str( o );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_LOCAL )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ /*
+ * This should be left recursive group of compile_appends
+ */
+ PARSE * vars = parse->left;
+
+ /* Special case an empty list of vars */
+ if ( vars->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_parse( parse->third, c, result_location );
+ nested_result = result_location;
+ }
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ else if ( vars->left->type == PARSE_NULL &&
+ vars->right->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->right->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL, name );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_ON )
+ {
+ int end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit_branch( c, INSTR_PUSH_ON, end );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_POP_ON, 0 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULE )
+ {
+ PARSE * p;
+ int n = 0;
+ VAR_PARSE_GROUP * group;
+ const char * s = object_str( parse->string );
+
+ if ( parse->left->left == NULL && parse->left->right->type == PARSE_NULL )
+ ;
+ else
+ for ( p = parse->left; p; p = p->left )
+ {
+ compile_parse( p->right, c, RESULT_STACK );
+ ++n;
+ }
+
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_emit( c, INSTR_CALL_RULE, n );
+ compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULES )
+ {
+ do compile_parse( parse->left, c, RESULT_NONE );
+ while ( ( parse = parse->right )->type == PARSE_RULES );
+ compile_parse( parse, c, result_location );
+ }
+ else if ( parse->type == PARSE_SET )
+ {
+ PARSE * vars = parse->left;
+ unsigned int op_code;
+ unsigned int op_code_group;
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
+ case ASSIGN_APPEND: op_code = INSTR_APPEND; op_code_group = INSTR_APPEND_GROUP; break;
+ case ASSIGN_DEFAULT: op_code = INSTR_DEFAULT; op_code_group = INSTR_DEFAULT_GROUP; break;
+ }
+
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ if ( vars->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SETCOMP )
+ {
+ int n_args;
+ struct arg_list * args = arg_list_compile( parse->right, &n_args );
+
+ int rule_id = compile_emit_rule( c, parse->string, parse->left, n_args, args, parse->num );
+
+ compile_emit( c, INSTR_RULE, rule_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETEXEC )
+ {
+ int actions_id = compile_emit_actions( c, parse );
+
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ compile_emit( c, INSTR_ACTIONS, actions_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETTINGS )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->third, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: compile_emit( c, INSTR_SET_ON, 0 ); break;
+ case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break;
+ case ASSIGN_DEFAULT: compile_emit( c, INSTR_DEFAULT_ON, 0 ); break;
+ }
+
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SWITCH )
+ {
+ int switch_end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ for ( parse = parse->right; parse; parse = parse->right )
+ {
+ int id = compile_emit_constant( c, parse->left->string );
+ int next_case = compile_new_label( c );
+ compile_emit( c, INSTR_PUSH_CONSTANT, id );
+ compile_emit_branch( c, INSTR_JUMP_NOT_GLOB, next_case );
+ compile_parse( parse->left->left, c, result_location );
+ compile_emit_branch( c, INSTR_JUMP, switch_end );
+ compile_set_label( c, next_case );
+ }
+ compile_emit( c, INSTR_POP, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ compile_set_label( c, switch_end );
+ }
+ else if ( parse->type == PARSE_NULL )
+ {
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else
+ {
+ assert( !"unknown PARSE type." );
+ }
+}
+
+OBJECT * function_rulename( FUNCTION * function )
+{
+ return function->rulename;
+}
+
+void function_set_rulename( FUNCTION * function, OBJECT * rulename )
+{
+ function->rulename = rulename;
+}
+
+void function_location( FUNCTION * function_, OBJECT * * file, int * line )
+{
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#ifdef HAVE_PYTHON
+ if ( function_->type == FUNCTION_PYTHON )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
+ assert( function_->type == FUNCTION_JAM );
+ *file = function->file;
+ *line = function->line;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments );
+
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args )
+{
+ BUILTIN_FUNCTION * result = BJAM_MALLOC( sizeof( BUILTIN_FUNCTION ) );
+ result->base.type = FUNCTION_BUILTIN;
+ result->base.reference_count = 1;
+ result->base.rulename = 0;
+ result->base.formal_arguments = arg_list_compile_builtin( args, &result->base.num_formal_arguments );
+ result->func = func;
+ result->flags = flags;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile( PARSE * parse )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ compiler_init( c );
+ compile_parse( parse, c, RESULT_RETURN );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( parse->file );
+ result->line = parse->line;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ VAR_PARSE_ACTIONS * parse;
+ current_file = object_str( file );
+ current_line = line;
+ parse = parse_actions( actions );
+ compiler_init( c );
+ var_parse_actions_compile( parse, c );
+ var_parse_actions_free( parse );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( file );
+ result->line = line;
+ return (FUNCTION *)result;
+}
+
+static void argument_list_print( struct arg_list * args, int num_args );
+
+
+/* Define delimiters for type check elements in argument lists (and return type
+ * specifications, eventually).
+ */
+# define TYPE_OPEN_DELIM '['
+# define TYPE_CLOSE_DELIM ']'
+
+/*
+ * is_type_name() - true iff the given string represents a type check
+ * specification.
+ */
+
+int is_type_name( const char * s )
+{
+ return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
+ ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
+}
+
+static void argument_error( const char * message, FUNCTION * procedure, FRAME * frame, OBJECT * arg )
+{ extern void print_source_line( FRAME * );
+ LOL * actual = frame->args;
+ backtrace_line( frame->prev );
+ printf( "*** argument error\n* rule %s ( ", frame->rulename );
+ argument_list_print( procedure->formal_arguments, procedure->num_formal_arguments );
+ printf( " )\n* called with: ( " );
+ lol_print( actual );
+ printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
+ function_location( procedure, &frame->file, &frame->line );
+ print_source_line( frame );
+ printf( "see definition of rule '%s' being called\n", frame->rulename );
+ backtrace( frame->prev );
+ exit( 1 );
+}
+
+static void type_check_range
+(
+ OBJECT * type_name,
+ LISTITER iter,
+ LISTITER end,
+ FRAME * caller,
+ FUNCTION * called,
+ OBJECT * arg_name
+)
+{
+ static module_t * typecheck = 0;
+
+ /* If nothing to check, bail now. */
+ if ( iter == end || !type_name )
+ return;
+
+ if ( !typecheck )
+ {
+ typecheck = bindmodule( constant_typecheck );
+ }
+
+ /* If the checking rule can not be found, also bail. */
+ if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
+ return;
+
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ LIST *error;
+ FRAME frame[1];
+ frame_init( frame );
+ frame->module = typecheck;
+ frame->prev = caller;
+ frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
+
+ /* Prepare the argument list */
+ lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) );
+ error = evaluate_rule( type_name, frame );
+
+ if ( !list_empty( error ) )
+ argument_error( object_str( list_front( error ) ), called, caller, arg_name );
+
+ frame_free( frame );
+ }
+}
+
+static void type_check
+(
+ OBJECT * type_name,
+ LIST * values,
+ FRAME * caller,
+ FUNCTION * called,
+ OBJECT * arg_name
+)
+{
+ type_check_range( type_name, list_begin( values ), list_end( values ), caller, called, arg_name );
+}
+
+void argument_list_check( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_push( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, STACK * s )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ value = list_new( object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ value = list_new( object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ value = list_copy_range( actual, actual_iter, actual_end );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ type_check( formal_arg->type_name, value, frame, function, formal_arg->arg_name );
+
+ if ( formal_arg->index != -1 )
+ {
+ LIST * * old = &frame->module->fixed_variables[ formal_arg->index ];
+ stack_push( s, *old );
+ *old = value;
+ }
+ else
+ {
+ stack_push( s, var_swap( frame->module, formal_arg->arg_name, value ) );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_pop( struct arg_list * formal, int formal_count, FRAME * frame, STACK * s )
+{
+ int i, j;
+
+ for ( i = formal_count - 1; i >= 0; --i )
+ {
+ for ( j = formal[i].size - 1; j >= 0 ; --j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+
+ if ( formal_arg->flags == ARG_VARIADIC )
+ {
+ continue;
+ }
+ else if ( formal_arg->index != -1 )
+ {
+ LIST * old = stack_pop( s );
+ LIST * * pos = &frame->module->fixed_variables[ formal_arg->index ];
+ list_free( *pos );
+ *pos = old;
+ }
+ else
+ {
+ var_set( frame->module, formal_arg->arg_name, stack_pop( s ), VAR_SET );
+ }
+ }
+ }
+}
+
+
+struct argument_compiler
+{
+ struct dynamic_array args[ 1 ];
+ struct argument arg;
+ int state;
+#define ARGUMENT_COMPILER_START 0
+#define ARGUMENT_COMPILER_FOUND_TYPE 1
+#define ARGUMENT_COMPILER_FOUND_OBJECT 2
+#define ARGUMENT_COMPILER_DONE 3
+};
+
+
+static void argument_compiler_init( struct argument_compiler * c )
+{
+ dynamic_array_init( c->args );
+ c->state = ARGUMENT_COMPILER_START;
+}
+
+static void argument_compiler_free( struct argument_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg, OBJECT * file, int line )
+{
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+
+ if ( object_equal( arg, constant_question_mark ) )
+ {
+ c->arg.flags = ARG_OPTIONAL;
+ }
+ else if ( object_equal( arg, constant_plus ) )
+ {
+ c->arg.flags = ARG_PLUS;
+ }
+ else if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_STAR;
+ }
+
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_START;
+
+ if ( c->arg.flags != ARG_ONE )
+ break;
+ /* fall-through */
+
+ case ARGUMENT_COMPILER_START:
+
+ c->arg.type_name = 0;
+ c->arg.index = -1;
+ c->arg.flags = ARG_ONE;
+
+ if ( is_type_name( object_str( arg ) ) )
+ {
+ c->arg.type_name = object_copy( arg );
+ c->state = ARGUMENT_COMPILER_FOUND_TYPE;
+ break;
+ }
+ /* fall-through */
+
+ case ARGUMENT_COMPILER_FOUND_TYPE:
+
+ if ( is_type_name( object_str( arg ) ) )
+ {
+ printf( "%s:%d: missing argument name before type name: %s\n", object_str( file ), line, object_str( arg ) );
+ exit( 1 );
+ }
+
+ c->arg.arg_name = object_copy( arg );
+ if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_VARIADIC;
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_DONE;
+ }
+ else
+ {
+ c->state = ARGUMENT_COMPILER_FOUND_OBJECT;
+ }
+ break;
+
+ case ARGUMENT_COMPILER_DONE:
+ break;
+ }
+}
+
+static void argument_compiler_recurse( struct argument_compiler * c, PARSE * parse )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ argument_compiler_recurse( c, parse->left );
+ argument_compiler_recurse( c, parse->right );
+ }
+ else if ( parse->type != PARSE_NULL )
+ {
+ assert( parse->type == PARSE_LIST );
+ argument_compiler_add( c, parse->string, parse->file, parse->line );
+ }
+}
+
+static struct arg_list arg_compile_impl( struct argument_compiler * c, OBJECT * file, int line )
+{
+ struct arg_list result;
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_START:
+ case ARGUMENT_COMPILER_DONE:
+ break;
+ case ARGUMENT_COMPILER_FOUND_TYPE:
+ printf( "%s:%d: missing argument name after type name: %s\n", object_str( file ), line, object_str( c->arg.type_name ) );
+ exit( 1 );
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+ dynamic_array_push( c->args, c->arg );
+ break;
+ }
+ result.size = c->args->size;
+ result.args = BJAM_MALLOC( c->args->size * sizeof( struct argument ) );
+ memcpy( result.args, c->args->data, c->args->size * sizeof( struct argument ) );
+ return result;
+}
+
+static struct arg_list arg_compile( PARSE * parse )
+{
+ struct argument_compiler c[ 1 ];
+ struct arg_list result;
+ argument_compiler_init( c );
+ argument_compiler_recurse( c, parse );
+ result = arg_compile_impl( c, parse->file, parse->line );
+ argument_compiler_free( c );
+ return result;
+}
+
+struct argument_list_compiler
+{
+ struct dynamic_array args[ 1 ];
+};
+
+static void argument_list_compiler_init( struct argument_list_compiler * c )
+{
+ dynamic_array_init( c->args );
+}
+
+static void argument_list_compiler_free( struct argument_list_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+static void argument_list_compiler_add( struct argument_list_compiler * c, PARSE * parse )
+{
+ struct arg_list args = arg_compile( parse );
+ dynamic_array_push( c->args, args );
+}
+
+static void argument_list_compiler_recurse( struct argument_list_compiler * c, PARSE * parse )
+{
+ if ( parse )
+ {
+ argument_list_compiler_add( c, parse->right );
+ argument_list_compiler_recurse( c, parse->left );
+ }
+}
+
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments )
+{
+ if ( parse )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ argument_list_compiler_recurse( c, parse );
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments )
+{
+ if ( args )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ while ( *args )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ argument_compiler_init( arg_comp );
+ for ( ; *args; ++args )
+ {
+ OBJECT * token;
+ if ( strcmp( *args, ":" ) == 0 )
+ {
+ ++args;
+ break;
+ }
+ token = object_new( *args );
+ argument_compiler_add( arg_comp, token, constant_builtin, -1 );
+ object_free( token );
+ }
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ }
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static void argument_list_print( struct arg_list * args, int num_args )
+{
+ if ( args )
+ {
+ int i, j;
+ for ( i = 0; i < num_args; ++i )
+ {
+ if ( i ) printf(" : ");
+ for ( j = 0; j < args[ i ].size; ++j )
+ {
+ struct argument * formal_arg = &args[ i ].args[ j ];
+ if ( j ) printf( " " );
+ if ( formal_arg->type_name ) printf( "%s ", object_str( formal_arg->type_name ) );
+ printf( "%s", formal_arg->arg_name );
+ switch( formal_arg->flags )
+ {
+ case ARG_OPTIONAL: printf( " ?" ); break;
+ case ARG_PLUS: printf( " +" ); break;
+ case ARG_STAR: printf( " *" ); break;
+ }
+ }
+ }
+ }
+}
+
+
+struct arg_list * argument_list_bind_variables( struct arg_list * formal, int formal_count, module_t * module, int * counter )
+{
+ if ( formal )
+ {
+ struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof( struct arg_list ) * formal_count );
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ struct argument * args = (struct argument *)BJAM_MALLOC( sizeof( struct argument ) * formal[ i ].size );
+ for ( j = 0; j < formal[ i ].size; ++j )
+ {
+ args[ j ] = formal[ i ].args[ j ];
+ if ( args[ j ].type_name )
+ args[ j ].type_name = object_copy( args[ j ].type_name );
+ args[ j ].arg_name = object_copy( args[ j ].arg_name );
+ if ( args[ j ].flags != ARG_VARIADIC )
+ {
+ args[ j ].index = module_add_fixed_var( module, args[ j ].arg_name, counter );
+ }
+ }
+ result[ i ].args = args;
+ result[ i ].size = formal[ i ].size;
+ }
+
+ return result;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void argument_list_free( struct arg_list * args, int args_count )
+{
+ int i, j;
+ for ( i = 0; i < args_count; ++i )
+ {
+ for ( j = 0; j < args[ i ].size; ++j )
+ {
+ if ( args[ i ].args[ j ].type_name )
+ object_free( args[ i ].args[ j ].type_name );
+ object_free( args[ i ].args[ j ].arg_name );
+ }
+ BJAM_FREE( args[ i ].args );
+ }
+ BJAM_FREE( args );
+}
+
+
+FUNCTION * function_unbind_variables( FUNCTION * f )
+{
+ if ( f->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ if ( func->generic )
+ return func->generic;
+ else
+ return (FUNCTION *)func;
+ }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ assert( f->type == FUNCTION_BUILTIN );
+ return f;
+ }
+}
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter )
+{
+ if ( f->type == FUNCTION_BUILTIN )
+ {
+ return f;
+ }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
+ instruction * code;
+ int i;
+ assert( f->type == FUNCTION_JAM );
+ memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
+ new_func->base.reference_count = 1;
+ new_func->base.formal_arguments = argument_list_bind_variables( f->formal_arguments, f->num_formal_arguments, module, counter );
+ new_func->code = BJAM_MALLOC( func->code_size * sizeof( instruction ) );
+ memcpy( new_func->code, func->code, func->code_size * sizeof( instruction ) );
+ new_func->generic = (FUNCTION *)func;
+ func = new_func;
+ for ( i = 0; ; ++i )
+ {
+ OBJECT * key;
+ int op_code;
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_VAR: op_code = INSTR_PUSH_VAR_FIXED; break;
+ case INSTR_PUSH_LOCAL: op_code = INSTR_PUSH_LOCAL_FIXED; break;
+ case INSTR_POP_LOCAL: op_code = INSTR_POP_LOCAL_FIXED; break;
+ case INSTR_SET: op_code = INSTR_SET_FIXED; break;
+ case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break;
+ case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break;
+ case INSTR_RETURN: return (FUNCTION *)new_func;
+ case INSTR_CALL_RULE: ++i; continue;
+ case INSTR_PUSH_MODULE:
+ {
+ int depth = 1;
+ ++i;
+ while ( depth > 0 )
+ {
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_MODULE:
+ case INSTR_CLASS:
+ ++depth;
+ break;
+ case INSTR_POP_MODULE:
+ --depth;
+ break;
+ case INSTR_CALL_RULE:
+ ++i;
+ break;
+ }
+ ++i;
+ }
+ --i;
+ }
+ default: continue;
+ }
+ key = func->constants[ code->arg ];
+ if ( !( object_equal( key, constant_TMPDIR ) ||
+ object_equal( key, constant_TMPNAME ) ||
+ object_equal( key, constant_TMPFILE ) ||
+ object_equal( key, constant_STDOUT ) ||
+ object_equal( key, constant_STDERR ) ) )
+ {
+ code->op_code = op_code;
+ code->arg = module_add_fixed_var( module, key, counter );
+ }
+ }
+ }
+}
+
+void function_refer( FUNCTION * func )
+{
+ ++func->reference_count;
+}
+
+void function_free( FUNCTION * function_ )
+{
+ int i;
+
+ if ( --function_->reference_count != 0 ) return;
+
+ if ( function_->formal_arguments ) argument_list_free( function_->formal_arguments, function_->num_formal_arguments );
+
+ if ( function_->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
+
+ BJAM_FREE( func->code );
+
+ if ( func->generic )
+ function_free( func->generic );
+ else
+ {
+ if ( function_->rulename ) object_free( function_->rulename );
+
+ for ( i = 0; i < func->num_constants; ++i )
+ {
+ object_free( func->constants[i] );
+ }
+ BJAM_FREE( func->constants );
+
+ for ( i = 0; i < func->num_subfunctions; ++i )
+ {
+ object_free( func->functions[i].name );
+ function_free( func->functions[i].code );
+ }
+ BJAM_FREE( func->functions );
+
+ for ( i = 0; i < func->num_subactions; ++i )
+ {
+ object_free( func->actions[i].name );
+ function_free( func->actions[i].command );
+ }
+ BJAM_FREE( func->actions );
+
+ object_free( func->file );
+ }
+ }
+#ifdef HAVE_PYTHON
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * func = (PYTHON_FUNCTION *)function_;
+ Py_DECREF( func->python_function );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+#endif
+ else
+ {
+ assert( function_->type == FUNCTION_BUILTIN );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+
+ BJAM_FREE( function_ );
+}
+
+
+/* Alignment check for stack */
+
+struct align_var_edits
+{
+ char ch;
+ VAR_EDITS e;
+};
+
+struct align_expansion_item
+{
+ char ch;
+ expansion_item e;
+};
+
+static char check_align_var_edits[ sizeof(struct align_var_edits) <= sizeof(VAR_EDITS) + sizeof(void *) ? 1 : -1 ];
+static char check_align_expansion_item[ sizeof(struct align_expansion_item) <= sizeof(expansion_item) + sizeof(void *) ? 1 : -1 ];
+
+static char check_ptr_size1[ sizeof(LIST *) <= sizeof(void *) ? 1 : -1 ];
+static char check_ptr_size2[ sizeof(char *) <= sizeof(void *) ? 1 : -1 ];
+
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out )
+{
+ *(string * *)stack_allocate( s, sizeof( string * ) ) = out;
+ list_free( function_run( function, frame, s ) );
+ stack_deallocate( s, sizeof( string * ) );
+}
+
+/*
+ * WARNING: The instruction set is tuned for Jam and
+ * is not really generic. Be especially careful about
+ * stack push/pop.
+ */
+
+LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
+{
+ JAM_FUNCTION * function;
+ instruction * code;
+ LIST * l;
+ LIST * r;
+ LIST * result = L0;
+ void * saved_stack = s->data;
+
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ if ( function_->formal_arguments )
+ argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame );
+ return f->func( frame, f->flags );
+ }
+
+#ifdef HAVE_PYTHON
+
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_;
+ return call_python_function( f, frame );
+ }
+
+#endif
+
+ assert( function_->type == FUNCTION_JAM );
+
+ if ( function_->formal_arguments )
+ argument_list_push( function_->formal_arguments, function_->num_formal_arguments, function_, frame, s );
+
+ function = (JAM_FUNCTION *)function_;
+ code = function->code;
+ for ( ; ; )
+ {
+ switch ( code->op_code )
+ {
+
+ /*
+ * Basic stack manipulation
+ */
+
+ case INSTR_PUSH_EMPTY:
+ {
+ stack_push( s, L0 );
+ break;
+ }
+
+ case INSTR_PUSH_CONSTANT:
+ {
+ OBJECT * value = function_get_constant( function, code->arg );
+ stack_push( s, list_new( object_copy( value ) ) );
+ break;
+ }
+
+ case INSTR_PUSH_ARG:
+ {
+ stack_push( s, frame_get_local( frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_VAR:
+ {
+ stack_push( s, function_get_variable( function, frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_VAR_FIXED:
+ {
+ stack_push( s, list_copy( frame->module->fixed_variables[ code->arg ] ) );
+ break;
+ }
+
+ case INSTR_PUSH_GROUP:
+ {
+ LIST * value = L0;
+ LISTITER iter, end;
+ l = stack_pop( s );
+ for ( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ LIST * one = function_get_named_variable( function, frame, list_item( iter ) );
+ value = list_append( value, one );
+ }
+ list_free( l );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_PUSH_APPEND:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ stack_push( s, list_append( l, r ) );
+ break;
+ }
+
+ case INSTR_SWAP:
+ {
+ l = stack_top( s );
+ stack_set( s, 0, stack_at( s, code->arg ) );
+ stack_set( s, code->arg, l );
+ break;
+ }
+
+ case INSTR_POP:
+ {
+ list_free( stack_pop( s ) );
+ break;
+ }
+
+ /*
+ * Branch instructions
+ */
+
+ case INSTR_JUMP:
+ {
+ code += code->arg;
+ break;
+ }
+
+ case INSTR_JUMP_EMPTY:
+ {
+ l = stack_pop( s );
+ if ( !list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_NOT_EMPTY:
+ {
+ l = stack_pop( s );
+ if( list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_LT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) < 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_LE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) <= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) > 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) >= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_EQ:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( list_cmp( l, r ) == 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_NE:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if( list_cmp(l, r) != 0 ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_IN:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if ( list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_NOT_IN:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( !list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ /*
+ * For
+ */
+
+ case INSTR_FOR_INIT:
+ {
+ l = stack_top( s );
+ *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) =
+ list_begin( l );
+ break;
+ }
+
+ case INSTR_FOR_LOOP:
+ {
+ LISTITER iter = *(LISTITER *)stack_get( s );
+ stack_deallocate( s, sizeof( LISTITER ) );
+ l = stack_top( s );
+ if( iter == list_end( l ) )
+ {
+ list_free( stack_pop( s ) );
+ code += code->arg;
+ }
+ else
+ {
+ r = list_new( object_copy( list_item( iter ) ) );
+ iter = list_next( iter );
+ *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = iter;
+ stack_push( s, r );
+ }
+ break;
+ }
+
+ /*
+ * Switch
+ */
+
+ case INSTR_JUMP_NOT_GLOB:
+ {
+ const char * pattern;
+ const char * match;
+ l = stack_pop( s );
+ r = stack_top( s );
+ pattern = !list_empty( l ) ? object_str( list_front( l ) ) : "";
+ match = !list_empty( r ) ? object_str( list_front( r ) ) : "";
+ if( glob( pattern, match ) )
+ {
+ code += code->arg;
+ }
+ else
+ {
+ list_free( stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * Return
+ */
+
+ case INSTR_SET_RESULT:
+ {
+ list_free( result );
+ result = stack_pop( s );
+ break;
+ }
+
+ case INSTR_PUSH_RESULT:
+ {
+ stack_push( s, result );
+ result = L0;
+ break;
+ }
+
+ case INSTR_RETURN:
+ {
+ if ( function_->formal_arguments )
+ argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
+#ifndef NDEBUG
+
+ if ( !( saved_stack == s->data ) )
+ {
+ frame->file = function->file;
+ frame->line = function->line;
+ backtrace_line( frame );
+ printf( "error: stack check failed.\n" );
+ backtrace( frame );
+ assert( saved_stack == s->data );
+ }
+#endif
+ assert( saved_stack == s->data );
+ return result;
+ }
+
+ /*
+ * Local variables
+ */
+
+ case INSTR_PUSH_LOCAL:
+ {
+ LIST * value = stack_pop( s );
+ stack_push( s, function_swap_variable( function, frame, code->arg, value ) );
+ break;
+ }
+
+ case INSTR_POP_LOCAL:
+ {
+ function_set_variable( function, frame, code->arg, stack_pop( s ) );
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ stack_push( s, *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_POP_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LISTITER iter, end;
+ l = stack_pop( s );
+ for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ LIST * saved = function_swap_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ stack_push( s, saved );
+ }
+ list_free( value );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_POP_LOCAL_GROUP:
+ {
+ LISTITER iter, end;
+ r = stack_pop( s );
+ l = list_reverse( r );
+ list_free( r );
+ for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ function_set_named_variable( function, frame, list_item( iter ), stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * on $(TARGET) variables
+ */
+
+ case INSTR_PUSH_ON:
+ {
+ LIST * targets = stack_top( s );
+ if ( !list_empty( targets ) )
+ {
+ /*
+ * FIXME: push the state onto the stack instead of
+ * using pushsettings.
+ */
+ TARGET * t = bindtarget( list_front( targets ) );
+ pushsettings( frame->module, t->settings );
+ }
+ else
+ {
+ /*
+ * [ on $(TARGET) ... ] is ignored if $(TARGET) is empty.
+ */
+ list_free( stack_pop( s ) );
+ stack_push( s, L0 );
+ code += code->arg;
+ }
+ break;
+ }
+
+ case INSTR_POP_ON:
+ {
+ LIST * result = stack_pop( s );
+ LIST * targets = stack_pop( s );
+ if ( !list_empty( targets ) )
+ {
+ TARGET * t = bindtarget( list_front( targets ) );
+ popsettings( frame->module, t->settings );
+ }
+ list_free( targets );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_SET_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_SET, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_APPEND, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_DEFAULT, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Variable setting
+ */
+
+ case INSTR_SET:
+ {
+ function_set_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_APPEND:
+ {
+ function_append_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT:
+ {
+ function_default_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_SET_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = list_copy( stack_top( s ) );
+ break;
+ }
+
+ case INSTR_APPEND_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ *ptr = list_append( *ptr, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ if ( list_empty( *ptr ) )
+ *ptr = list_copy( stack_top( s ) );
+ break;
+ }
+
+ case INSTR_SET_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_set_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_append_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_default_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Rules
+ */
+
+ case INSTR_CALL_RULE:
+ {
+ const char * unexpanded =
+ object_str( function_get_constant( function, code[1].op_code ) );
+ LIST * result = function_call_rule( function, frame, s, code->arg, unexpanded, function->file, code[1].arg );
+ stack_push( s, result );
+ ++code;
+ break;
+ }
+
+ case INSTR_RULE:
+ {
+ function_set_rule( function, frame, s, code->arg );
+ break;
+ }
+
+ case INSTR_ACTIONS:
+ {
+ function_set_actions( function, frame, s, code->arg );
+ break;
+ }
+
+ /*
+ * Variable expansion
+ */
+
+ case INSTR_APPLY_MODIFIERS:
+ {
+ int n;
+ int i;
+ l = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, l );
+ l = apply_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX:
+ {
+ l = apply_subscript( s );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS:
+ {
+ int i;
+ int n;
+ l = stack_pop( s );
+ r = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, r );
+ stack_push( s, l );
+ l = apply_subscript_and_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_GROUP:
+ {
+ LIST * vars = stack_pop( s );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_subscript( s ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ list_free( stack_pop( s ) );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ LIST * r = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ stack_push( s, r );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_subscript_and_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( stack_pop( s ) );
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_COMBINE_STRINGS:
+ {
+ LIST * result;
+ size_t buffer_size = code->arg * sizeof( expansion_item );
+ LIST * * stack_pos = stack_get( s );
+ expansion_item * items = stack_allocate( s, buffer_size );
+ int i;
+ for( i = 0; i < code->arg; ++i )
+ {
+ items[i].saved = stack_pos[i];
+ items[i].elem = list_begin( items[i].saved );
+ }
+ result = expand( items, code->arg );
+ stack_deallocate( s, buffer_size );
+ for( i = 0; i < code->arg; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_INCLUDE:
+ {
+ LIST * nt = stack_pop( s );
+
+ if ( !list_empty( nt ) )
+ {
+ TARGET * t = bindtarget( list_front( nt ) );
+ list_free( nt );
+
+ /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
+ * prevents an included file from being treated as part of the body of a
+ * rule. I did not see any reason to do that, so I lifted the
+ * restriction.
+ */
+
+ /* Bind the include file under the influence of */
+ /* "on-target" variables. Though they are targets, */
+ /* include files are not built with make(). */
+
+ pushsettings( root_module(), t->settings );
+ /* We don't expect that file to be included is generated by some
+ action. Therefore, pass 0 as third argument.
+ If the name resolves to directory, let it error out. */
+ object_free( t->boundname );
+ t->boundname = search( t->name, &t->time, 0, 0 );
+ popsettings( root_module(), t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ break;
+ }
+
+ /*
+ * Classes and modules
+ */
+
+ case INSTR_PUSH_MODULE:
+ {
+ LIST * module_name = stack_pop( s );
+
+ module_t * outer_module = frame->module;
+ frame->module = !list_empty( module_name ) ? bindmodule( list_front( module_name ) ) : root_module();
+
+ list_free( module_name );
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_POP_MODULE:
+ {
+ module_t * outer_module = *(module_t * *)stack_get( s );
+ stack_deallocate( s, sizeof( module_t * ) );
+ frame->module = outer_module;
+ break;
+ }
+
+ case INSTR_CLASS:
+ {
+ LIST * bases = stack_pop( s );
+ LIST * name = stack_pop( s );
+ OBJECT * class_module = make_class_module( name, bases, frame );
+
+ module_t * outer_module = frame->module;
+ frame->module = bindmodule( class_module );
+ object_free( class_module );
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_BIND_MODULE_VARIABLES:
+ {
+ module_bind_variables( frame->module );
+ break;
+ }
+
+ case INSTR_APPEND_STRINGS:
+ {
+ string buf[1];
+ string_new( buf );
+ combine_strings( s, code->arg, buf );
+ stack_push( s, list_new( object_new( buf->value ) ) );
+ string_free( buf );
+ break;
+ }
+
+ case INSTR_WRITE_FILE:
+ {
+ string buf[1];
+ const char * out;
+ OBJECT * tmp_filename = 0;
+ int out_debug = DEBUG_EXEC ? 1 : 0;
+ FILE * out_file = 0;
+ string_new( buf );
+ combine_strings( s, code->arg, buf );
+ out = object_str( list_front( stack_top( s ) ) );
+
+ /* For stdout/stderr we will create a temp file and generate
+ * a command that outputs the content as needed.
+ */
+ if ( ( strcmp( "STDOUT", out ) == 0 ) ||
+ ( strcmp( "STDERR", out ) == 0 ) )
+ {
+ int err_redir = strcmp( "STDERR", out ) == 0;
+ string result[1];
+ tmp_filename = path_tmpfile();
+ string_new( result );
+
+ #ifdef OS_NT
+ string_append( result, "type \"" );
+ #else
+ string_append( result, "cat \"" );
+ #endif
+ string_append( result, object_str( tmp_filename ) );
+ string_push_back( result, '\"' );
+ if ( err_redir )
+ string_append( result, " 1>&2" );
+
+ /* Replace STDXXX with the temporary file. */
+ list_free( stack_pop( s ) );
+ stack_push( s, list_new( object_new( result->value ) ) );
+ out = object_str( tmp_filename );
+
+ string_free( result );
+
+ /* We also make sure that the temp files created by this
+ * get nuked eventually.
+ */
+ file_remove_atexit( tmp_filename );
+ }
+
+ if ( !globs.noexec )
+ {
+ string out_name[1];
+ /* Handle "path to file" filenames. */
+ if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) )
+ {
+ string_copy( out_name, out + 1 );
+ string_truncate( out_name, out_name->size - 1 );
+ }
+ else
+ {
+ string_copy( out_name, out );
+ }
+ out_file = fopen( out_name->value, "w" );
+
+ if ( !out_file )
+ {
+ printf( "failed to write output file '%s'!\n", out_name->value );
+ exit( EXITBAD );
+ }
+ string_free( out_name );
+ }
+
+ if ( out_debug ) printf( "\nfile %s\n", out );
+
+ if ( out_file ) fputs( buf->value, out_file );
+ if ( out_debug ) fputs( buf->value, stdout );
+
+ if ( out_file )
+ {
+ fflush( out_file );
+ fclose( out_file );
+ }
+ string_free( buf );
+ if ( tmp_filename )
+ object_free( tmp_filename );
+
+ if ( out_debug ) fputc( '\n', stdout );
+
+ break;
+ }
+
+ case INSTR_OUTPUT_STRINGS:
+ {
+ string * buf = *(string * *)( (char *)stack_get( s ) + ( code->arg * sizeof( LIST * ) ) );
+ combine_strings( s, code->arg, buf );
+ break;
+ }
+
+ }
+ ++code;
+ }
+}
+
+
+#ifdef HAVE_PYTHON
+
+static struct arg_list * arg_list_compile_python( PyObject * bjam_signature, int * num_arguments )
+{
+ if ( bjam_signature )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ Py_ssize_t s, i, j, inner;
+ argument_list_compiler_init( c );
+
+ s = PySequence_Size( bjam_signature );
+ for ( i = 0; i < s; ++i )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ PyObject * v = PySequence_GetItem( bjam_signature, i );
+ argument_compiler_init( arg_comp );
+
+ inner = PySequence_Size( v );
+ for ( j = 0; j < inner; ++j )
+ {
+ PyObject * x = PySequence_GetItem( v, j );
+ argument_compiler_add( arg_comp, object_new( PyString_AsString( x ) ), constant_builtin, -1 );
+ }
+
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ Py_DECREF( v );
+ }
+
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature )
+{
+ PYTHON_FUNCTION * result = BJAM_MALLOC( sizeof( PYTHON_FUNCTION ) );
+
+ result->base.type = FUNCTION_PYTHON;
+ result->base.reference_count = 1;
+ result->base.rulename = 0;
+ result->base.formal_arguments = arg_list_compile_python( bjam_signature, &result->base.num_formal_arguments );
+ Py_INCREF( function );
+ result->python_function = function;
+
+ return (FUNCTION *)result;
+}
+
+static void argument_list_to_python( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, PyObject * kw )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ PyObject * value;
+ LIST * l;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = 0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ l = list_copy_range( actual, actual_iter, actual_end );
+ value = list_to_python( l );
+ list_free( l );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ if (value)
+ {
+ PyObject * key = PyString_FromString( object_str( formal_arg->arg_name ) );
+ PyDict_SetItem( kw, key, value );
+ Py_DECREF( key );
+ Py_DECREF( value );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+/* Given a Python object, return a string to use in Jam
+ code instead of said object.
+ If the object is string, use the string value
+ If the object implemenets __jam_repr__ method, use that.
+ Otherwise return 0. */
+OBJECT * python_to_string( PyObject * value )
+{
+ if ( PyString_Check( value ) )
+ {
+ return object_new( PyString_AsString( value ) );
+ }
+ else
+ {
+ /* See if this is an instance that defines special __jam_repr__
+ method. */
+ if ( PyInstance_Check( value )
+ && PyObject_HasAttrString( value, "__jam_repr__" ) )
+ {
+ PyObject* repr = PyObject_GetAttrString( value, "__jam_repr__" );
+ if ( repr )
+ {
+ PyObject * arguments2 = PyTuple_New( 0 );
+ PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
+ Py_DECREF( repr );
+ Py_DECREF( arguments2 );
+ if ( PyString_Check( value2 ) )
+ {
+ return object_new( PyString_AsString( value2 ) );
+ }
+ Py_DECREF( value2 );
+ }
+ }
+ return 0;
+ }
+}
+
+static module_t * python_module()
+{
+ static module_t * python = 0;
+ if ( !python )
+ python = bindmodule(constant_python);
+ return python;
+}
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame )
+{
+ LIST * result = 0;
+ PyObject * arguments = 0;
+ PyObject * kw = NULL;
+ int i ;
+ PyObject * py_result;
+ FRAME * prev_frame_before_python_call;
+
+ if ( function->base.formal_arguments )
+ {
+ arguments = PyTuple_New(0);
+ kw = PyDict_New();
+
+ argument_list_to_python( function->base.formal_arguments, function->base.num_formal_arguments, &function->base, frame, kw );
+ }
+ else
+ {
+ arguments = PyTuple_New( frame->args->count );
+ for ( i = 0; i < frame->args->count; ++i )
+ {
+ PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args, i ) ) );
+ }
+ }
+
+ frame->module = python_module();
+
+ prev_frame_before_python_call = frame_before_python_call;
+ frame_before_python_call = frame;
+ py_result = PyObject_Call( function->python_function, arguments, kw );
+ frame_before_python_call = prev_frame_before_python_call;
+ Py_DECREF( arguments );
+ Py_XDECREF( kw );
+ if ( py_result != NULL )
+ {
+ if ( PyList_Check( py_result ) )
+ {
+ int size = PyList_Size( py_result );
+ int i;
+ for ( i = 0; i < size; ++i )
+ {
+ PyObject * item = PyList_GetItem( py_result, i );
+ OBJECT *s = python_to_string( item );
+ if ( !s ) {
+ fprintf( stderr, "Non-string object returned by Python call.\n" );
+ } else {
+ result = list_push_back( result, s );
+ }
+ }
+ }
+ else if ( py_result == Py_None )
+ {
+ result = L0;
+ }
+ else
+ {
+ OBJECT *s = python_to_string( py_result );
+ if (s)
+ result = list_new( s );
+ else
+ /* We have tried all we could. Return empty list. There are
+ cases, e.g. feature.feature function that should return
+ value for the benefit of Python code and which also can be
+ called by Jam code, where no sensible value can be
+ returned. We cannot even emit a warning, since there will
+ be a pile of them. */
+ result = L0;
+ }
+
+ Py_DECREF( py_result );
+ }
+ else
+ {
+ PyErr_Print();
+ fprintf( stderr,"Call failed\n" );
+ }
+
+ return result;
+}
+
+#endif
+
+
+void function_done( void )
+{
+ BJAM_FREE( stack );
+}
diff --git a/tools/build/v2/engine/function.h b/tools/build/v2/engine/function.h
new file mode 100644
index 0000000000..64f26b3cf7
--- /dev/null
+++ b/tools/build/v2/engine/function.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#ifndef FUNCTION_SW20111123_H
+#define FUNCTION_SW20111123_H
+
+#include "object.h"
+#include "frames.h"
+#include "lists.h"
+#include "parse.h"
+#include "strings.h"
+
+typedef struct _function FUNCTION;
+typedef struct _stack STACK;
+
+STACK * stack_global( void );
+void stack_push( STACK * s, LIST * l );
+LIST * stack_pop( STACK * s );
+
+FUNCTION * function_compile( PARSE * parse );
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args );
+void function_refer( FUNCTION * );
+void function_free( FUNCTION * );
+OBJECT * function_rulename( FUNCTION * );
+void function_set_rulename( FUNCTION *, OBJECT * );
+void function_location( FUNCTION *, OBJECT * *, int * );
+LIST * function_run( FUNCTION * function, FRAME * frame, STACK * s );
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line );
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out );
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+void function_done( void );
+
+#ifdef HAVE_PYTHON
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/glob.c b/tools/build/v2/engine/glob.c
index 527d6c8088..bec00ee562 100644
--- a/tools/build/v2/engine/glob.c
+++ b/tools/build/v2/engine/glob.c
@@ -29,17 +29,17 @@
# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
-static void globchars( char * s, char * e, char * b );
+static void globchars( const char * s, const char * e, char * b );
/*
* glob() - match a string against a simple pattern.
*/
-int glob( char * c, char * s )
+int glob( const char * c, const char * s )
{
char bitlist[ BITLISTSIZE ];
- char * here;
+ const char * here;
for ( ; ; )
switch ( *c++ )
@@ -64,7 +64,7 @@ int glob( char * c, char * s )
globchars( here, c, bitlist );
- if ( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
+ if ( !CHECK_BIT( bitlist, *(const unsigned char *)s ) )
return 1;
++s;
break;
@@ -111,7 +111,7 @@ int glob( char * c, char * s )
* globchars() - build a bitlist to check for character group match.
*/
-static void globchars( char * s, char * e, char * b )
+static void globchars( const char * s, const char * e, char * b )
{
int neg = 0;
diff --git a/tools/build/v2/engine/hash.c b/tools/build/v2/engine/hash.c
index fbd1a8993d..6e748ab4d0 100644
--- a/tools/build/v2/engine/hash.c
+++ b/tools/build/v2/engine/hash.c
@@ -7,6 +7,7 @@
# include "jam.h"
# include "hash.h"
# include "compile.h"
+# include "object.h"
# include <assert.h>
/*
@@ -29,30 +30,16 @@
#define HASH_DEBUG_PROFILE 1
/* */
-char *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
-
/* Header attached to all data items entered into a hash table. */
struct hashhdr
{
struct item * next;
- unsigned int keyval; /* for quick comparisons */
-};
-
-/* This structure overlays the one handed to hashenter(). Its actual size is
- * given to hashinit().
- */
-
-struct hashdata
-{
- char * key;
- /* rest of user data */
};
typedef struct item
{
struct hashhdr hdr;
- struct hashdata data;
} ITEM ;
# define MAX_LISTS 32
@@ -78,7 +65,6 @@ struct hash
int more; /* how many more ITEMs fit in lists[ list ] */
ITEM *free; /* free list of items */
char *next; /* where to put more ITEMs in lists[ list ] */
- int datalen; /* length of records in this hash table */
int size; /* sizeof( ITEM ) + aligned datalen */
int nel; /* total ITEMs held by all lists[] */
int list; /* index into lists[] */
@@ -89,54 +75,23 @@ struct hash
} lists[ MAX_LISTS ];
} items;
- char * name; /* just for hashstats() */
+ const char * name; /* just for hashstats() */
};
static void hashrehash( struct hash *hp );
static void hashstat( struct hash *hp );
-static void * hash_mem_alloc(size_t datalen, size_t size);
-static void hash_mem_free(size_t datalen, void * data);
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp);
-#endif
-
-static unsigned int jenkins_one_at_a_time_hash(const unsigned char *key)
-{
- unsigned int hash = 0;
-
- while ( *key )
- {
- hash += *key++;
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
-
- return hash;
-}
-
-/*
-static unsigned int knuth_hash(const unsigned char *key)
-{
- unsigned int keyval = *key;
- while ( *key )
- keyval = keyval * 2147059363 + *key++;
- return keyval;
-}
-*/
-static unsigned int hash_keyval( const char * key_ )
+static unsigned int hash_keyval( OBJECT * key )
{
- /*
- return knuth_hash((const unsigned char *)key_);
- */
- return jenkins_one_at_a_time_hash((const unsigned char *)key_);
+ return object_hash( key );
}
#define hash_bucket(hp,keyval) ((hp)->tab.base + ( (keyval) % (hp)->tab.nel ))
+#define hash_data_key(data) (*(OBJECT * *)(data))
+#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(struct hashhdr)))
+#define hash_item_key(item) (hash_data_key(hash_item_data(item)))
+
/* Find the hash item for the given data. Returns pointer to the
item and if given a pointer to the item before the found item.
If it's the first item in a bucket, there is no previous item,
@@ -145,7 +100,7 @@ static unsigned int hash_keyval( const char * key_ )
static ITEM * hash_search(
struct hash *hp,
unsigned int keyval,
- const char * keydata,
+ OBJECT * keydata,
ITEM * * previous )
{
ITEM * i = *hash_bucket(hp,keyval);
@@ -153,8 +108,7 @@ static ITEM * hash_search(
for ( ; i; i = i->hdr.next )
{
- if ( ( keyval == i->hdr.keyval ) &&
- !strcmp( i->data.key, keydata ) )
+ if ( object_equal( hash_item_key( i ), keydata ) )
{
if (previous)
{
@@ -169,52 +123,13 @@ static ITEM * hash_search(
}
/*
- * hash_free() - remove the given item from the table if it's there.
- * Returns 1 if found, 0 otherwise.
- *
- * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
- */
-int
-hash_free(
- register struct hash *hp,
- HASHDATA *data)
-{
- ITEM * i = 0;
- ITEM * prev = 0;
- unsigned int keyval = hash_keyval(data->key);
-
- i = hash_search( hp, keyval, data->key, &prev );
- if (i)
- {
- /* mark it free so we skip it during enumeration */
- i->data.key = 0;
- /* unlink the record from the hash chain */
- if (prev) prev->hdr.next = i->hdr.next;
- else *hash_bucket(hp,keyval) = i->hdr.next;
- /* link it into the freelist */
- i->hdr.next = hp->items.free;
- hp->items.free = i;
- /* we have another item */
- hp->items.more++;
-
- return 1;
- }
- return 0;
-}
-
-/*
- * hashitem() - find a record in the table, and optionally enter a new one
+ * hash_insert() - insert a record in the table or return the existing one
*/
-int
-hashitem(
- register struct hash *hp,
- HASHDATA **data,
- int enter )
+HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
{
- register ITEM *i;
- char *b = (*data)->key;
- unsigned int keyval = hash_keyval(b);
+ ITEM * i;
+ unsigned int keyval = hash_keyval( key );
#ifdef HASH_DEBUG_PROFILE
profile_frame prof[1];
@@ -222,38 +137,24 @@ hashitem(
profile_enter( 0, prof );
#endif
- if ( enter && !hp->items.more )
+ if ( !hp->items.more )
hashrehash( hp );
- if ( !enter && !hp->items.nel )
+ i = hash_search( hp, keyval, key, 0 );
+ if ( i )
{
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE )
- profile_exit( prof );
- #endif
- return 0;
+ *found = 1;
}
-
- i = hash_search( hp, keyval, (*data)->key, 0 );
- if (i)
- {
- *data = &i->data;
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE ) profile_exit( prof );
- #endif
- return !0;
- }
-
- if ( enter )
+ else
{
- ITEM * * base = hash_bucket(hp,keyval);
+ ITEM * * base = hash_bucket( hp, keyval );
/* try to grab one from the free list */
if ( hp->items.free )
{
i = hp->items.free;
hp->items.free = i->hdr.next;
- assert( i->data.key == 0 );
+ assert( hash_item_key( i ) == 0 );
}
else
{
@@ -261,24 +162,58 @@ hashitem(
hp->items.next += hp->items.size;
}
hp->items.more--;
- memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
- i->hdr.keyval = keyval;
i->hdr.next = *base;
*base = i;
- *data = &i->data;
- #ifdef OPT_BOEHM_GC
- if (sizeof(HASHDATA) == hp->items.datalen)
- {
- GC_REGISTER_FINALIZER(i->data.key,&hash_mem_finalizer,hp,0,0);
- }
+ *found = 0;
+ }
+
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
+ #endif
+
+ return hash_item_data( i );
+}
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+
+HASHDATA * hash_find( struct hash *hp, OBJECT *key )
+{
+ ITEM *i;
+ unsigned int keyval = hash_keyval(key);
+
+ #ifdef HASH_DEBUG_PROFILE
+ profile_frame prof[1];
+ if ( DEBUG_PROFILE )
+ profile_enter( 0, prof );
+ #endif
+
+ if ( !hp->items.nel )
+ {
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
#endif
+ return 0;
}
+ i = hash_search( hp, keyval, key, 0 );
+
#ifdef HASH_DEBUG_PROFILE
if ( DEBUG_PROFILE )
profile_exit( prof );
#endif
- return 0;
+
+ if (i)
+ {
+ return hash_item_data( i );
+ }
+ else
+ {
+ return 0;
+ }
}
/*
@@ -289,7 +224,7 @@ static void hashrehash( register struct hash *hp )
{
int i = ++hp->items.list;
hp->items.more = i ? 2 * hp->items.nel : hp->inel;
- hp->items.next = (char *)hash_mem_alloc( hp->items.datalen, hp->items.more * hp->items.size );
+ hp->items.next = (char *)BJAM_MALLOC( hp->items.more * hp->items.size );
hp->items.free = 0;
hp->items.lists[i].nel = hp->items.more;
@@ -297,10 +232,10 @@ static void hashrehash( register struct hash *hp )
hp->items.nel += hp->items.more;
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
hp->tab.nel = hp->items.nel * hp->bloat;
- hp->tab.base = (ITEM **)hash_mem_alloc( hp->items.datalen, hp->tab.nel * sizeof(ITEM **) );
+ hp->tab.base = (ITEM **)BJAM_MALLOC( hp->tab.nel * sizeof(ITEM **) );
memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
@@ -312,9 +247,9 @@ static void hashrehash( register struct hash *hp )
for ( ; nel--; next += hp->items.size )
{
register ITEM *i = (ITEM *)next;
- ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
+ ITEM **ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
/* code currently assumes rehashing only when there are no free items */
- assert( i->data.key != 0 );
+ assert( hash_item_key( i ) != 0 );
i->hdr.next = *ip;
*ip = i;
@@ -335,8 +270,8 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
for ( ; nel--; next += hp->items.size )
{
ITEM * i = (ITEM *)next;
- if ( i->data.key != 0 ) /* DO not enumerate freed items. */
- f( &i->data, data );
+ if ( hash_item_key( i ) != 0 ) /* DO not enumerate freed items. */
+ f( hash_item_data( i ), data );
}
}
}
@@ -352,16 +287,15 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
struct hash *
hashinit(
int datalen,
- char *name )
+ const char *name )
{
- struct hash *hp = (struct hash *)hash_mem_alloc( datalen, sizeof( *hp ) );
+ struct hash *hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
hp->bloat = 3;
hp->tab.nel = 0;
hp->tab.base = (ITEM **)0;
hp->items.more = 0;
hp->items.free = 0;
- hp->items.datalen = datalen;
hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
hp->items.list = -1;
hp->items.nel = 0;
@@ -371,89 +305,92 @@ hashinit(
return hp;
}
+void hashdone( struct hash * hp )
+{
+ if ( !hp )
+ return;
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ hashstat( hp );
+ hash_free( hp );
+}
+
/*
- * hashdone() - free a hash table, given its handle
+ * hash_free() - free a hash table, given its handle
*/
void
-hashdone( struct hash *hp )
+hash_free( struct hash * hp )
{
int i;
if ( !hp )
return;
- if ( DEBUG_MEM || DEBUG_PROFILE )
- hashstat( hp );
-
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
for ( i = 0; i <= hp->items.list; ++i )
- hash_mem_free( hp->items.datalen, hp->items.lists[i].base );
- hash_mem_free( hp->items.datalen, (char *)hp );
+ BJAM_FREE( hp->items.lists[i].base );
+ BJAM_FREE( (char *)hp );
}
-static void * hash_mem_alloc(size_t datalen, size_t size)
-{
- if (sizeof(HASHDATA) == datalen)
- {
- return BJAM_MALLOC_RAW(size);
- }
- else
- {
- return BJAM_MALLOC(size);
- }
-}
-static void hash_mem_free(size_t datalen, void * data)
+/* ---- */
+
+static void hashstat( struct hash * hp )
{
- if (sizeof(HASHDATA) == datalen)
- {
- BJAM_FREE_RAW(data);
- }
- else
- {
- BJAM_FREE(data);
- }
+ struct hashstats stats[ 1 ];
+ hashstats_init( stats );
+ hashstats_add( stats, hp );
+ hashstats_print( stats, hp->name );
}
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp)
+void hashstats_init( struct hashstats * stats )
{
- HASHDATA d;
- d.key = key;
- hash_free(hp,&d);
+ stats->count = 0;
+ stats->num_items = 0;
+ stats->tab_size = 0;
+ stats->item_size = 0;
+ stats->sets = 0;
}
-#endif
-
-/* ---- */
-
-static void hashstat( struct hash * hp )
+void hashstats_add( struct hashstats * stats, struct hash * hp )
{
- ITEM * * tab = hp->tab.base;
- int nel = hp->tab.nel;
- int count = 0;
- int sets = 0;
- int run = ( tab[ nel - 1 ] != (ITEM *)0 );
- int i;
- int here;
-
- for ( i = nel; i > 0; --i )
+ if ( hp )
{
- if ( ( here = ( *tab++ != (ITEM *)0 ) ) )
- count++;
- if ( here && !run )
- sets++;
- run = here;
+ ITEM * * tab = hp->tab.base;
+ int nel = hp->tab.nel;
+ int count = 0;
+ int sets = 0;
+ int i;
+
+ for ( i = 0; i < nel; ++i )
+ {
+ ITEM * item;
+ int here = 0;
+ for ( item = tab[ i ]; item != 0; item = item->hdr.next )
+ ++here;
+
+ count += here;
+ if ( here > 0 )
+ ++sets;
+ }
+
+ stats->count += count;
+ stats->sets += sets;
+ stats->num_items += hp->items.nel;
+ stats->tab_size += hp->tab.nel;
+ stats->item_size = hp->items.size;
}
+}
+void hashstats_print( struct hashstats * stats, const char * name )
+{
printf( "%s table: %d+%d+%d (%dK+%luK) items+table+hash, %f density\n",
- hp->name,
- count,
- hp->items.nel,
- hp->tab.nel,
- hp->items.nel * hp->items.size / 1024,
- (long unsigned)hp->tab.nel * sizeof( ITEM ** ) / 1024,
- (float)count / (float)sets );
+ name,
+ stats->count,
+ stats->num_items,
+ stats->tab_size,
+ stats->num_items * stats->item_size / 1024,
+ (long unsigned)stats->tab_size * sizeof( ITEM ** ) / 1024,
+ (float)stats->count / (float)stats->sets );
}
diff --git a/tools/build/v2/engine/hash.h b/tools/build/v2/engine/hash.h
index 7195b4146f..65db56c1c5 100644
--- a/tools/build/v2/engine/hash.h
+++ b/tools/build/v2/engine/hash.h
@@ -11,15 +11,68 @@
#ifndef BOOST_JAM_HASH_H
#define BOOST_JAM_HASH_H
+/*
+ * An opaque struct representing an item in the
+ * hash table. The first element of every struct
+ * stored in the table must be an OBJECT * which
+ * is treated as the key.
+ */
typedef struct hashdata HASHDATA;
-struct hash * hashinit ( int datalen, char * name );
-int hashitem ( struct hash * hp, HASHDATA * * data, int enter );
-void hashdone ( struct hash * hp );
+/*
+ * hashinit() - initialize a hash table, returning a handle.
+ * datalen is the size of the items. name is used for debugging.
+ */
+struct hash * hashinit ( int datalen, const char * name );
+
+/*
+ * hash_free() - free a hash table, given its handle
+ */
+void hash_free( struct hash * hp );
+void hashdone( struct hash * hp );
+
+/*
+ * hashenumerate() - call f(i, data) on each item, i in the hash
+ * table. The order of the items is unspecified.
+ */
void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
-int hash_free ( struct hash * hp, HASHDATA * data);
-#define hashenter( hp, data ) ( !hashitem( hp, data, !0 ) )
-#define hashcheck( hp, data ) hashitem( hp, data, 0 )
+/*
+ * hash_insert() - insert a new item in a hash table, or return an
+ * existing one.
+ *
+ * Preconditions:
+ * - hp must be a hash table created by hashinit
+ * - key must be an object created by object_new
+ *
+ * Postconditions:
+ * - if the key does not already exist in the hash
+ * table, *found == 0 and the result will be a
+ * pointer to an uninitialized item. The key
+ * of the new item must be set to a value equal to
+ * key before any further operations on the
+ * hash table except hashdone.
+ * - if the key is present then *found == 1 and
+ * the result is a pointer to the existing
+ * record.
+ */
+HASHDATA * hash_insert ( struct hash * hp, OBJECT * key, int * found );
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+HASHDATA * hash_find ( struct hash * hp, OBJECT * key );
+
+struct hashstats {
+ int count;
+ int num_items;
+ int tab_size;
+ int item_size;
+ int sets;
+};
+
+void hashstats_init( struct hashstats * stats );
+void hashstats_add( struct hashstats * stats, struct hash * hp );
+void hashstats_print( struct hashstats * stats, const char * name );
#endif
diff --git a/tools/build/v2/engine/hcache.c b/tools/build/v2/engine/hcache.c
index 70bb798cc9..9e7a0343ed 100644
--- a/tools/build/v2/engine/hcache.c
+++ b/tools/build/v2/engine/hcache.c
@@ -8,11 +8,12 @@
# include "rules.h"
# include "regexp.h"
# include "headers.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "hcache.h"
# include "variable.h"
# include "search.h"
+# include "modules.h"
#ifdef OPT_HEADER_CACHE_EXT
@@ -43,7 +44,7 @@ typedef struct hcachedata HCACHEDATA ;
struct hcachedata
{
- char * boundname;
+ OBJECT * boundname;
time_t time;
LIST * includes;
LIST * hdrscan; /* the HDRSCAN value for this target */
@@ -70,30 +71,30 @@ static int hits = 0;
* the result so the user can not change the cache file during header scanning.
*/
-static char * cache_name( void )
+static const char * cache_name( void )
{
- static char * name = 0;
+ static OBJECT * name = 0;
if ( !name )
{
- LIST * hcachevar = var_get( "HCACHEFILE" );
+ LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );
- if ( hcachevar )
+ if ( !list_empty( hcachevar ) )
{
- TARGET * t = bindtarget( hcachevar->string );
+ TARGET * t = bindtarget( list_front( hcachevar ) );
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
/* Do not expect the cache file to be generated, so pass 0 as the
* third argument to search. Expect the location to be specified via
* LOCATE, so pass 0 as the fourth arugment.
*/
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
- if ( hcachevar )
- name = copystr( t->boundname );
+ name = object_copy( t->boundname );
}
}
- return name;
+ return name ? object_str( name ) : 0;
}
@@ -105,10 +106,10 @@ static char * cache_name( void )
static int cache_maxage( void )
{
int age = 100;
- LIST * var = var_get( "HCACHEMAXAGE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
+ if ( !list_empty( var ) )
{
- age = atoi( var->string );
+ age = atoi( object_str( list_front( var ) ) );
if ( age < 0 )
age = 0;
}
@@ -118,10 +119,10 @@ static int cache_maxage( void )
/*
* Read a netstring. The caveat is that the string can not contain ASCII 0. The
- * returned value is as returned by newstr(), so it need not be freed.
+ * returned value is as returned by object_new().
*/
-char * read_netstring( FILE * f )
+OBJECT * read_netstring( FILE * f )
{
unsigned long len;
static char * buf = NULL;
@@ -154,7 +155,7 @@ char * read_netstring( FILE * f )
return NULL;
buf[ len ] = 0;
- return newstr( buf );
+ return object_new( buf );
}
@@ -172,12 +173,13 @@ void write_netstring( FILE * f, char const * s )
void hcache_init()
{
- HCACHEDATA cachedata;
- HCACHEDATA * c;
FILE * f;
- char * version;
+ OBJECT * version = 0;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
+
+ if ( hcachehash )
+ return;
hcachehash = hashinit( sizeof( HCACHEDATA ), "hcache" );
@@ -188,105 +190,144 @@ void hcache_init()
return;
version = read_netstring( f );
- if ( !version || strcmp( version, CACHE_FILE_VERSION ) )
- {
- fclose( f );
- return;
- }
+
+ if ( !version || strcmp( object_str( version ), CACHE_FILE_VERSION ) )
+ goto bail;
while ( 1 )
{
- char * record_type;
- char * time_str;
- char * age_str;
- char * includes_count_str;
- char * hdrscan_count_str;
- int i;
- int count;
- LIST * l;
+ HCACHEDATA cachedata;
+ HCACHEDATA * c;
+ OBJECT * record_type = 0;
+ OBJECT * time_str = 0;
+ OBJECT * age_str = 0;
+ OBJECT * includes_count_str = 0;
+ OBJECT * hdrscan_count_str = 0;
+ int i;
+ int count;
+ LIST * l;
+ int found;
+
+ cachedata.boundname = 0;
+ cachedata.includes = 0;
+ cachedata.hdrscan = 0;
record_type = read_netstring( f );
if ( !record_type )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- if ( !strcmp( record_type, CACHE_RECORD_END ) )
+ if ( !strcmp( object_str( record_type ), CACHE_RECORD_END ) )
+ {
+ object_free( record_type );
break;
- if ( strcmp( record_type, CACHE_RECORD_HEADER ) )
+ }
+ if ( strcmp( object_str( record_type ), CACHE_RECORD_HEADER ) )
{
fprintf( stderr, "invalid %s with record separator <%s>\n",
- hcachename, record_type ? record_type : "<null>" );
- goto bail;
+ hcachename, record_type ? object_str( record_type ) : "<null>" );
+ goto cleanup;
}
- c = &cachedata;
-
- c->boundname = read_netstring( f );
- time_str = read_netstring( f );
- age_str = read_netstring( f );
- includes_count_str = read_netstring( f );
+ cachedata.boundname = read_netstring( f );
+ time_str = read_netstring( f );
+ age_str = read_netstring( f );
+ includes_count_str = read_netstring( f );
- if ( !c->boundname || !time_str || !age_str || !includes_count_str )
+ if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- c->time = atoi( time_str );
- c->age = atoi( age_str ) + 1;
+ cachedata.time = atoi( object_str( time_str ) );
+ cachedata.age = atoi( object_str( age_str ) ) + 1;
- count = atoi( includes_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( includes_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->includes = l;
+ cachedata.includes = l;
hdrscan_count_str = read_netstring( f );
- if ( !includes_count_str )
+ if ( !hdrscan_count_str )
{
- list_free( c->includes );
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- count = atoi( hdrscan_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( hdrscan_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->hdrscan = l;
+ cachedata.hdrscan = l;
- if ( !hashenter( hcachehash, (HASHDATA * *)&c ) )
+ c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found );
+ if ( !found )
+ {
+ c->boundname = cachedata.boundname;
+ c->time = cachedata.time;
+ c->includes = cachedata.includes;
+ c->hdrscan = cachedata.hdrscan;
+ c->age = cachedata.age;
+ }
+ else
{
fprintf( stderr, "can't insert header cache item, bailing on %s\n",
hcachename );
- goto bail;
+ goto cleanup;
}
c->next = hcachelist;
hcachelist = c;
++header_count;
+
+ object_free( record_type );
+ object_free( time_str );
+ object_free( age_str );
+ object_free( includes_count_str );
+ object_free( hdrscan_count_str );
+ continue;
+
+cleanup:
+
+ if ( record_type ) object_free( record_type );
+ if ( time_str ) object_free( time_str );
+ if ( age_str ) object_free( age_str );
+ if ( includes_count_str ) object_free( includes_count_str );
+ if ( hdrscan_count_str ) object_free( hdrscan_count_str );
+
+ if ( cachedata.boundname ) object_free( cachedata.boundname );
+ if ( cachedata.includes ) list_free( cachedata.includes );
+ if ( cachedata.hdrscan ) list_free( cachedata.hdrscan );
+
+ goto bail;
}
if ( DEBUG_HEADER )
printf( "hcache read from file %s\n", hcachename );
- bail:
+bail:
+ if ( version )
+ object_free( version );
fclose( f );
}
@@ -296,17 +337,17 @@ void hcache_done()
FILE * f;
HCACHEDATA * c;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
int maxage;
if ( !hcachehash )
return;
if ( !( hcachename = cache_name() ) )
- return;
+ goto cleanup;
if ( !( f = fopen( hcachename, "wb" ) ) )
- return;
+ goto cleanup;
maxage = cache_maxage();
@@ -316,7 +357,7 @@ void hcache_done()
c = hcachelist;
for ( c = hcachelist; c; c = c->next )
{
- LIST * l;
+ LISTITER iter, end;
char time_str[ 30 ];
char age_str[ 30 ];
char includes_count_str[ 30 ];
@@ -333,15 +374,17 @@ void hcache_done()
sprintf( age_str, "%lu", (long unsigned) c->age );
write_netstring( f, CACHE_RECORD_HEADER );
- write_netstring( f, c->boundname );
+ write_netstring( f, object_str( c->boundname ) );
write_netstring( f, time_str );
write_netstring( f, age_str );
write_netstring( f, includes_count_str );
- for ( l = c->includes; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->includes ), end = list_end( c->includes );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
write_netstring( f, hdrscan_count_str );
- for ( l = c->hdrscan; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->hdrscan ), end = list_end( c->hdrscan );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
fputs( "\n", f );
++header_count;
}
@@ -352,81 +395,110 @@ void hcache_done()
hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
fclose ( f );
+
+cleanup:
+ for ( c = hcachelist; c; c = c->next )
+ {
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ object_free( c->boundname );
+ }
+
+ hcachelist = 0;
+ if ( hcachehash )
+ hashdone( hcachehash );
+ hcachehash = 0;
}
LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
{
- HCACHEDATA cachedata;
- HCACHEDATA * c = &cachedata;
+ HCACHEDATA * c;
LIST * l = 0;
++queries;
- c->boundname = t->boundname;
-
- if (hashcheck (hcachehash, (HASHDATA **) &c))
- {
- if (c->time == t->time)
+ if ( ( c = (HCACHEDATA *)hash_find( hcachehash, t->boundname ) ) )
{
- LIST *l1 = hdrscan, *l2 = c->hdrscan;
- while (l1 && l2) {
- if (l1->string != l2->string) {
- l1 = NULL;
- } else {
- l1 = list_next(l1);
- l2 = list_next(l2);
- }
+ if ( c->time == t->time )
+ {
+ LIST *l1 = hdrscan, *l2 = c->hdrscan;
+ LISTITER iter1 = list_begin( l1 ), end1 = list_end( l1 ),
+ iter2 = list_begin( l2 ), end2 = list_end( l2 );
+ while ( iter1 != end1 && iter2 != end2 )
+ {
+ if ( !object_equal( list_item( iter1 ), list_item( iter2 ) ) )
+ {
+ iter1 = end1;
+ }
+ else
+ {
+ iter1 = list_next( iter1 );
+ iter2 = list_next( iter2 );
+ }
+ }
+ if ( iter1 != end1 || iter2 != end2 )
+ {
+ if (DEBUG_HEADER)
+ printf( "HDRSCAN out of date in cache for %s\n",
+ object_str( t->boundname ) );
+
+ printf( "HDRSCAN out of date for %s\n",
+ object_str( t->boundname ) );
+ printf(" real : ");
+ list_print( hdrscan );
+ printf( "\n cached: " );
+ list_print( c->hdrscan );
+ printf( "\n" );
+
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ c->includes = L0;
+ c->hdrscan = L0;
+ }
+ else
+ {
+ if (DEBUG_HEADER)
+ printf( "using header cache for %s\n",
+ object_str( t->boundname ) );
+ c->age = 0;
+ ++hits;
+ l = list_copy( c->includes );
+ return l;
+ }
}
- if (l1 || l2) {
- if (DEBUG_HEADER)
- printf("HDRSCAN out of date in cache for %s\n",
- t->boundname);
-
- printf("HDRSCAN out of date for %s\n", t->boundname);
- printf(" real : ");
- list_print(hdrscan);
- printf("\n cached: ");
- list_print(c->hdrscan);
- printf("\n");
-
- list_free(c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- } else {
- if (DEBUG_HEADER)
- printf ("using header cache for %s\n", t->boundname);
- c->age = 0;
- ++hits;
- l = list_copy (0, c->includes);
- return l;
+ else
+ {
+ if (DEBUG_HEADER)
+ printf ("header cache out of date for %s\n",
+ object_str( t->boundname ) );
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ c->includes = L0;
+ c->hdrscan = L0;
}
- } else {
- if (DEBUG_HEADER)
- printf ("header cache out of date for %s\n", t->boundname);
- list_free (c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- }
- } else {
- if (hashenter (hcachehash, (HASHDATA **)&c)) {
- c->boundname = newstr (c->boundname);
- c->next = hcachelist;
- hcachelist = c;
}
+ else
+ {
+ int found;
+ c = (HCACHEDATA *)hash_insert( hcachehash, t->boundname, &found );
+ if ( !found )
+ {
+ c->boundname = object_copy( t->boundname );
+ c->next = hcachelist;
+ hcachelist = c;
+ }
}
/* 'c' points at the cache entry. Its out of date. */
- l = headers1 (0, t->boundname, rec, re);
+ l = headers1( L0, t->boundname, rec, re );
c->time = t->time;
c->age = 0;
- c->includes = list_copy (0, l);
- c->hdrscan = list_copy(0, hdrscan);
+ c->includes = list_copy( l );
+ c->hdrscan = list_copy( hdrscan );
return l;
}
diff --git a/tools/build/v2/engine/hcache.h b/tools/build/v2/engine/hcache.h
index c316e3bcad..2aa2394939 100644
--- a/tools/build/v2/engine/hcache.h
+++ b/tools/build/v2/engine/hcache.h
@@ -11,8 +11,8 @@
# include "regexp.h"
# include "lists.h"
-void hcache_init(void);
-void hcache_done(void);
-LIST *hcache(TARGET *t, int rec, regexp *re[], LIST *hdrscan);
+void hcache_init( void );
+void hcache_done( void );
+LIST * hcache( TARGET *t, int rec, regexp * re[], LIST * hdrscan );
#endif
diff --git a/tools/build/v2/engine/hdrmacro.c b/tools/build/v2/engine/hdrmacro.c
index 43031d48ff..6ef2a131c9 100644
--- a/tools/build/v2/engine/hdrmacro.c
+++ b/tools/build/v2/engine/hdrmacro.c
@@ -19,7 +19,7 @@
# include "regexp.h"
# include "hdrmacro.h"
# include "hash.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -49,8 +49,8 @@
/* this type is used to store a dictionary of file header macros */
typedef struct header_macro
{
- char * symbol;
- char * filename; /* we could maybe use a LIST here ?? */
+ OBJECT * symbol;
+ OBJECT * filename; /* we could maybe use a LIST here ?? */
} HEADER_MACRO;
static struct hash * header_macros_hash = 0;
@@ -63,26 +63,28 @@ static struct hash * header_macros_hash = 0;
# define MAXINC 10
void
-macro_headers( TARGET *t )
+macro_headers( TARGET * t )
{
static regexp *re = 0;
FILE *f;
char buf[ 1024 ];
if ( DEBUG_HEADER )
- printf( "macro header scan for %s\n", t->name );
+ printf( "macro header scan for %s\n", object_str( t->name ) );
/* this regexp is used to detect lines of the form */
/* "#define MACRO <....>" or "#define MACRO "....." */
/* in the header macro files.. */
if ( re == 0 )
{
- re = regex_compile(
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
"[<\"]([^\">]*)[\">].*$" );
+ re = regex_compile( re_str );
+ object_free( re_str );
}
- if ( !( f = fopen( t->boundname, "r" ) ) )
+ if ( !( f = fopen( object_str( t->boundname ), "r" ) ) )
return;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -92,24 +94,30 @@ macro_headers( TARGET *t )
if ( regexec( re, buf ) && re->startp[1] )
{
+ OBJECT * symbol;
+ int found;
/* we detected a line that looks like "#define MACRO filename */
- re->endp[1][0] = '\0';
- re->endp[2][0] = '\0';
+ ((char *)re->endp[1])[0] = '\0';
+ ((char *)re->endp[2])[0] = '\0';
if ( DEBUG_HEADER )
printf( "macro '%s' used to define filename '%s' in '%s'\n",
- re->startp[1], re->startp[2], t->boundname );
+ re->startp[1], re->startp[2], object_str( t->boundname ) );
/* add macro definition to hash table */
if ( !header_macros_hash )
header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
- v->symbol = re->startp[1];
- v->filename = 0;
- if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+ symbol = object_new( re->startp[1] );
+ v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found );
+ if ( !found )
{
- v->symbol = newstr( re->startp[1] ); /* never freed */
- v->filename = newstr( re->startp[2] ); /* never freed */
+ v->symbol = symbol;
+ v->filename = object_new( re->startp[2] ); /* never freed */
+ }
+ else
+ {
+ object_free( symbol );
}
/* XXXX: FOR NOW, WE IGNORE MULTIPLE MACRO DEFINITIONS !! */
/* WE MIGHT AS WELL USE A LIST TO STORE THEM.. */
@@ -120,17 +128,14 @@ macro_headers( TARGET *t )
}
-char * macro_header_get( const char * macro_name )
+OBJECT * macro_header_get( OBJECT * macro_name )
{
- HEADER_MACRO var;
- HEADER_MACRO * v = &var;
-
- v->symbol = (char* )macro_name;
+ HEADER_MACRO * v;
- if ( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+ if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find( header_macros_hash, macro_name ) ) )
{
if ( DEBUG_HEADER )
- printf( "### macro '%s' evaluated to '%s'\n", macro_name, v->filename );
+ printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name ), object_str( v->filename ) );
return v->filename;
}
return 0;
diff --git a/tools/build/v2/engine/hdrmacro.h b/tools/build/v2/engine/hdrmacro.h
index 08cc111600..ddfa6eeac2 100644
--- a/tools/build/v2/engine/hdrmacro.h
+++ b/tools/build/v2/engine/hdrmacro.h
@@ -9,6 +9,11 @@
* #define MACRO "filename" definitions
*/
+#ifndef HDRMACRO_SW20111118_H
+#define HDRMACRO_SW20111118_H
+
void macro_headers( TARGET *t );
-char* macro_header_get( const char* macro_name );
+OBJECT * macro_header_get( OBJECT * macro_name );
+
+#endif
diff --git a/tools/build/v2/engine/headers.c b/tools/build/v2/engine/headers.c
index b9d8f6370d..7e01440169 100644
--- a/tools/build/v2/engine/headers.c
+++ b/tools/build/v2/engine/headers.c
@@ -14,11 +14,12 @@
# include "parse.h"
# include "compile.h"
# include "rules.h"
+# include "modules.h"
# include "variable.h"
# include "regexp.h"
# include "headers.h"
# include "hdrmacro.h"
-# include "newstr.h"
+# include "object.h"
#ifdef OPT_HEADER_CACHE_EXT
# include "hcache.h"
@@ -46,7 +47,7 @@
*/
#ifndef OPT_HEADER_CACHE_EXT
-static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
+static LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[]);
#endif
/*
@@ -56,28 +57,33 @@ static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
# define MAXINC 10
void
-headers( TARGET *t )
+headers( TARGET * t )
{
LIST * hdrscan;
LIST * hdrrule;
#ifndef OPT_HEADER_CACHE_EXT
- LIST * headlist = 0;
+ LIST * headlist = L0;
#endif
regexp * re[ MAXINC ];
int rec = 0;
+ LISTITER iter, end;
- if ( !( hdrscan = var_get( "HDRSCAN" ) ) ||
- !( hdrrule = var_get( "HDRRULE" ) ) )
+ hdrscan = var_get( root_module(), constant_HDRSCAN );
+ if ( list_empty( hdrscan ) )
+ return;
+
+ hdrrule = var_get( root_module(), constant_HDRRULE );
+ if ( list_empty( hdrrule ) )
return;
if ( DEBUG_HEADER )
- printf( "header scan %s\n", t->name );
+ printf( "header scan %s\n", object_str( t->name ) );
/* Compile all regular expressions in HDRSCAN */
- while ( ( rec < MAXINC ) && hdrscan )
+ iter = list_begin( hdrscan ), end = list_end( hdrscan );
+ for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
{
- re[ rec++ ] = regex_compile( hdrscan->string );
- hdrscan = list_next( hdrscan );
+ re[ rec++ ] = regex_compile( list_item( iter ) );
}
/* Doctor up call to HDRRULE rule */
@@ -85,7 +91,7 @@ headers( TARGET *t )
{
FRAME frame[1];
frame_init( frame );
- lol_add( frame->args, list_new( L0, t->name ) );
+ lol_add( frame->args, list_new( object_copy( t->name ) ) );
#ifdef OPT_HEADER_CACHE_EXT
lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
#else
@@ -96,9 +102,9 @@ headers( TARGET *t )
{
/* The third argument to HDRRULE is the bound name of
* $(<) */
- lol_add( frame->args, list_new( L0, t->boundname ) );
+ lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
- list_free( evaluate_rule( hdrrule->string, frame ) );
+ list_free( evaluate_rule( list_front( hdrrule ), frame ) );
}
/* Clean up. */
@@ -118,7 +124,7 @@ static LIST *
#endif
headers1(
LIST * l,
- char * file,
+ OBJECT * file,
int rec,
regexp * re[] )
{
@@ -137,10 +143,14 @@ headers1(
/* the following regexp is used to detect cases where a */
/* file is included through a line line "#include MACRO" */
if ( re_macros == 0 )
- re_macros = regex_compile(
+ {
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ re_macros = regex_compile( re_str );
+ object_free( re_str );
+ }
- if ( !( f = fopen( file, "r" ) ) )
+ if ( !( f = fopen( object_str( file ), "r" ) ) )
return l;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -158,30 +168,33 @@ headers1(
for ( i = 0; i < rec; ++i )
if ( regexec( re[i], buf ) && re[i]->startp[1] )
{
- re[i]->endp[1][0] = '\0';
+ ((char *)re[i]->endp[1])[0] = '\0';
if ( DEBUG_HEADER )
printf( "header found: %s\n", re[i]->startp[1] );
- l = list_new( l, newstr( re[i]->startp[1] ) );
+ l = list_push_back( l, object_new( re[i]->startp[1] ) );
}
/* special treatment for #include MACRO */
if ( regexec( re_macros, buf ) && re_macros->startp[1] )
{
- char* header_filename;
+ OBJECT * header_filename;
+ OBJECT * macro_name;
- re_macros->endp[1][0] = '\0';
+ ((char *)re_macros->endp[1])[0] = '\0';
if ( DEBUG_HEADER )
printf( "macro header found: %s", re_macros->startp[1] );
- header_filename = macro_header_get( re_macros->startp[1] );
+ macro_name = object_new( re_macros->startp[1] );
+ header_filename = macro_header_get( macro_name );
+ object_free( macro_name );
if ( header_filename )
{
if ( DEBUG_HEADER )
- printf( " resolved to '%s'\n", header_filename );
- l = list_new( l, newstr( header_filename ) );
+ printf( " resolved to '%s'\n", object_str( header_filename ) );
+ l = list_push_back( l, object_copy( header_filename ) );
}
else
{
@@ -197,7 +210,7 @@ headers1(
}
-void regerror( char * s )
+void regerror( const char * s )
{
printf( "re error %s\n", s );
}
diff --git a/tools/build/v2/engine/headers.h b/tools/build/v2/engine/headers.h
index 624475fe7d..1c0a642df8 100644
--- a/tools/build/v2/engine/headers.h
+++ b/tools/build/v2/engine/headers.h
@@ -8,9 +8,18 @@
* headers.h - handle #includes in source files
*/
-void headers( TARGET *t );
+#ifndef HEADERS_SW20111118_H
+#define HEADERS_SW20111118_H
+
+#include "object.h"
+#include "rules.h"
+#include "regexp.h"
+
+void headers( TARGET * t );
#ifdef OPT_HEADER_CACHE_EXT
struct regexp;
-LIST *headers1( LIST *l, char *file, int rec, struct regexp *re[] );
+LIST * headers1( LIST *l, OBJECT * file, int rec, struct regexp *re[] );
+#endif
+
#endif
diff --git a/tools/build/v2/engine/jam.c b/tools/build/v2/engine/jam.c
index e11d082bca..09faf85225 100644
--- a/tools/build/v2/engine/jam.c
+++ b/tools/build/v2/engine/jam.c
@@ -54,18 +54,18 @@
* are layered thus:
*
* variable|expand
- * / | | |
- * / | | |
- * / | | |
- * lists | | pathsys
- * \ | |
- * \ | |
- * \ | |
- * newstr |
+ * / | |
+ * / | |
+ * / | |
+ * lists | pathsys
+ * \ |
+ * \ hash
+ * \ |
+ * \ |
* \ |
* \ |
* \ |
- * hash
+ * object
*
* Roughly, the modules are:
*
@@ -73,8 +73,6 @@
* command.c - maintain lists of commands
* compile.c - compile parsed jam statements
* execunix.c - execute a shell script on UNIX
- * execvms.c - execute a shell script, ala VMS
- * expand.c - expand a buffer, given variable values
* file*.c - scan directories and archives on *
* hash.c - simple in-memory hashing routines
* hdrmacro.c - handle header file parsing for filename macro definitions
@@ -84,7 +82,7 @@
* lists.c - maintain lists of strings
* make.c - bring a target up to date, once rules are in place
* make1.c - execute command to bring targets up to date
- * newstr.c - string manipulation routines
+ * object.c - string manipulation routines
* option.c - command line option processing
* parse.c - make and destroy parse trees as driven by the parser
* path*.c - manipulate file names on *
@@ -115,14 +113,20 @@
#include "compile.h"
#include "builtins.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "scan.h"
#include "timestamp.h"
#include "make.h"
#include "strings.h"
-#include "expand.h"
#include "filesys.h"
#include "output.h"
+#include "search.h"
+#include "class.h"
+#include "execcmd.h"
+#include "constants.h"
+#include "function.h"
+#include "pwd.h"
+#include "hcache.h"
/* Macintosh is "special" */
#ifdef OS_MAC
@@ -196,7 +200,6 @@ static void run_unit_tests()
execnt_unit_test();
#endif
string_unit_test();
- var_expand_unit_test();
}
#endif
@@ -211,7 +214,9 @@ int anyhow = 0;
extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
#endif
-char *saved_argv0;
+void regex_done();
+
+const char *saved_argv0;
int main( int argc, char * * argv, char * * arg_environ )
{
@@ -223,6 +228,7 @@ int main( int argc, char * * argv, char * * arg_environ )
int arg_c = argc;
char * * arg_v = argv;
char const * progname = argv[0];
+ module_t * environ_module;
saved_argv0 = argv[0];
@@ -338,6 +344,8 @@ int main( int argc, char * * argv, char * * arg_environ )
globs.debug[i--] = 1;
}
+ constants_init();
+
{
PROFILE_ENTER( MAIN );
@@ -377,14 +385,14 @@ int main( int argc, char * * argv, char * * arg_environ )
#endif
/* Set JAMDATE. */
- var_set( "JAMDATE", list_new( L0, outf_time(time(0)) ), VAR_SET );
+ var_set( root_module(), constant_JAMDATE, list_new( outf_time(time(0)) ), VAR_SET );
/* Set JAM_VERSION. */
- var_set( "JAM_VERSION",
- list_new( list_new( list_new( L0,
- newstr( VERSION_MAJOR_SYM ) ),
- newstr( VERSION_MINOR_SYM ) ),
- newstr( VERSION_PATCH_SYM ) ),
+ var_set( root_module(), constant_JAM_VERSION,
+ list_push_back( list_push_back( list_new(
+ object_new( VERSION_MAJOR_SYM ) ),
+ object_new( VERSION_MINOR_SYM ) ),
+ object_new( VERSION_PATCH_SYM ) ),
VAR_SET );
/* Set JAMUNAME. */
@@ -394,17 +402,17 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( uname( &u ) >= 0 )
{
- var_set( "JAMUNAME",
- list_new(
- list_new(
- list_new(
- list_new(
- list_new( L0,
- newstr( u.sysname ) ),
- newstr( u.nodename ) ),
- newstr( u.release ) ),
- newstr( u.version ) ),
- newstr( u.machine ) ), VAR_SET );
+ var_set( root_module(), constant_JAMUNAME,
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_new(
+ object_new( u.sysname ) ),
+ object_new( u.nodename ) ),
+ object_new( u.release ) ),
+ object_new( u.version ) ),
+ object_new( u.machine ) ), VAR_SET );
}
}
#endif /* unix */
@@ -414,19 +422,18 @@ int main( int argc, char * * argv, char * * arg_environ )
/* First into the global module, with splitting, for backward
* compatibility.
*/
- var_defines( use_environ, 1 );
+ var_defines( root_module(), use_environ, 1 );
+ environ_module = bindmodule( constant_ENVIRON );
/* Then into .ENVIRON, without splitting. */
- enter_module( bindmodule(".ENVIRON") );
- var_defines( use_environ, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( environ_module, use_environ, 0 );
/*
* Jam defined variables OS & OSPLAT. We load them after environment, so
* that setting OS in environment does not change Jam's notion of the
* current platform.
*/
- var_defines( othersyms, 1 );
+ var_defines( root_module(), othersyms, 1 );
/* Load up variables set on command line. */
for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
@@ -434,16 +441,16 @@ int main( int argc, char * * argv, char * * arg_environ )
char *symv[2];
symv[ 0 ] = s;
symv[ 1 ] = 0;
- var_defines( symv, 1 );
- enter_module( bindmodule(".ENVIRON") );
- var_defines( symv, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( root_module(), symv, 1 );
+ var_defines( environ_module, symv, 0 );
}
/* Set the ARGV to reflect the complete list of arguments of invocation.
*/
for ( n = 0; n < arg_c; ++n )
- var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND );
+ {
+ var_set( root_module(), constant_ARGV, list_new( object_new( arg_v[n] ) ), VAR_APPEND );
+ }
/* Initialize built-in rules. */
load_builtins();
@@ -459,29 +466,43 @@ int main( int argc, char * * argv, char * * arg_environ )
}
else
{
- mark_target_for_updating( arg_v[ n ] );
+ OBJECT * target = object_new( arg_v[ n ] );
+ mark_target_for_updating( target );
+ object_free( target );
}
}
- if (!targets_to_update())
- mark_target_for_updating("all");
+ if ( list_empty( targets_to_update() ) )
+ {
+ mark_target_for_updating( constant_all );
+ }
/* Parse ruleset. */
{
FRAME frame[ 1 ];
frame_init( frame );
for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
- parse_file( s, frame );
+ {
+ OBJECT * filename = object_new( s );
+ parse_file( filename, frame );
+ object_free( filename );
+ }
if ( !n )
- parse_file( "+", frame );
+ {
+ parse_file( constant_plus, frame );
+ }
}
status = yyanyerrors();
/* Manually touch -t targets. */
for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
- touch_target( s );
+ {
+ OBJECT * target = object_new( s );
+ touch_target( target );
+ object_free( target );
+ }
/* If an output file is specified, set globs.cmdout to that. */
if ( ( s = getoptval( optv, 'o', 0 ) ) )
@@ -498,13 +519,13 @@ int main( int argc, char * * argv, char * * arg_environ )
options. */
{
LIST *p = L0;
- p = var_get ("PARALLELISM");
- if (p)
+ p = var_get ( root_module(), constant_PARALLELISM );
+ if ( !list_empty( p ) )
{
- int j = atoi (p->string);
- if (j == -1)
+ int j = atoi( object_str( list_front( p ) ) );
+ if ( j == -1 )
{
- printf( "Invalid value of PARALLELISM: %s\n", p->string);
+ printf( "Invalid value of PARALLELISM: %s\n", object_str( list_front( p ) ) );
}
else
{
@@ -516,11 +537,11 @@ int main( int argc, char * * argv, char * * arg_environ )
/* KEEP_GOING overrides -q option. */
{
LIST *p = L0;
- p = var_get ("KEEP_GOING");
- if (p)
+ p = var_get( root_module(), constant_KEEP_GOING );
+ if ( !list_empty( p ) )
{
- int v = atoi (p->string);
- if (v == 0)
+ int v = atoi( object_str( list_front( p ) ) );
+ if ( v == 0 )
globs.quitquick = 1;
else
globs.quitquick = 0;
@@ -532,16 +553,9 @@ int main( int argc, char * * argv, char * * arg_environ )
PROFILE_ENTER( MAIN_MAKE );
LIST * targets = targets_to_update();
- if (targets)
+ if ( !list_empty( targets ) )
{
- int targets_count = list_length( targets );
- const char * * targets2 = (const char * *)
- BJAM_MALLOC( targets_count * sizeof( char * ) );
- int n = 0;
- for ( ; targets; targets = list_next( targets ) )
- targets2[ n++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow );
- free( targets );
+ status |= make( targets, anyhow );
}
else
{
@@ -557,12 +571,28 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( DEBUG_PROFILE )
profile_dump();
+
+#ifdef OPT_HEADER_CACHE_EXT
+ hcache_done();
+#endif
+
+ clear_targets_to_update();
+
/* Widely scattered cleanup. */
- var_done();
file_done();
rules_done();
stamps_done();
- str_done();
+ search_done();
+ class_done();
+ modules_done();
+ regex_done();
+ exec_done();
+ pwd_done();
+ path_done();
+ function_done();
+ list_done();
+ constants_done();
+ object_done();
/* Close cmdout. */
if ( globs.cmdout )
@@ -579,7 +609,7 @@ int main( int argc, char * * argv, char * * arg_environ )
#if defined(_WIN32)
#include <windows.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf));
if (ret == 0 || ret == sizeof(buf)) return NULL;
@@ -587,7 +617,7 @@ char *executable_path(char *argv0) {
}
#elif defined(__APPLE__) /* Not tested */
#include <mach-o/dyld.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
uint32_t size = sizeof(buf);
int ret = _NSGetExecutablePath(buf, &size);
@@ -597,12 +627,12 @@ char *executable_path(char *argv0) {
#elif defined(sun) || defined(__sun) /* Not tested */
#include <stdlib.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
return strdup(getexecname());
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
@@ -616,16 +646,16 @@ char *executable_path(char *argv0) {
}
#elif defined(__linux__)
#include <unistd.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
if (ret == 0 || ret == sizeof(buf)) return NULL;
return strndup(buf, ret);
}
#else
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
/* If argv0 is absolute path, assume it's the right absolute path. */
- if (argv0[0] == "/")
+ if (argv0[0] == '/')
return strdup(argv0);
return NULL;
}
diff --git a/tools/build/v2/engine/jam.h b/tools/build/v2/engine/jam.h
index 73a7a04c58..26b94a7f7e 100644
--- a/tools/build/v2/engine/jam.h
+++ b/tools/build/v2/engine/jam.h
@@ -46,40 +46,6 @@
#define HAVE_POPEN 1
/*
- * VMS, OPENVMS
- */
-
-#ifdef VMS
-
-#include <types.h>
-#include <file.h>
-#include <stat.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <unixlib.h>
-
-#define OSMINOR "OS=VMS"
-#define OSMAJOR "VMS=true"
-#define OS_VMS
-#define MAXLINE 1024 /* longest 'together' actions */
-#define SPLITPATH ','
-#define EXITOK 1
-#define EXITBAD 0
-#define DOWNSHIFT_PATHS
-
-/* This may be inaccurate. */
-#ifndef __DECC
-#define OSPLAT "OSPLAT=VAX"
-#endif
-
-#endif
-
-/*
* Windows NT
*/
@@ -157,55 +123,6 @@
#endif
/*
- * OS2
- */
-
-#ifdef __OS2__
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-
-#define OSMAJOR "OS2=true"
-#define OSMINOR "OS=OS2"
-#define OS_OS2
-#define SPLITPATH ';'
-#define MAXLINE 996 /* longest 'together' actions */
-#define USE_EXECUNIX
-#define USE_PATHUNIX
-#define PATH_DELIM '\\'
-#define DOWNSHIFT_PATHS
-
-#ifdef __EMX__
- #define USE_FILEUNIX
-#endif
-
-#endif
-
-/*
- * Macintosh MPW
- */
-
-#ifdef macintosh
-
-#include <time.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#define OSMAJOR "MAC=true"
-#define OSMINOR "OS=MAC"
-#define OS_MAC
-#define SPLITPATH ','
-
-#endif
-
-/*
* God fearing UNIX.
*/
diff --git a/tools/build/v2/engine/jamgram.c b/tools/build/v2/engine/jamgram.c
index b1fa0835df..48c85228e8 100644
--- a/tools/build/v2/engine/jamgram.c
+++ b/tools/build/v2/engine/jamgram.c
@@ -1,30 +1,38 @@
-/* A Bison parser, made by GNU Bison 1.875. */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* A Bison parser, made by GNU Bison 2.4.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Written by Richard Stallman by simplifying the original so called
- ``semantic'' parser. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
@@ -36,17 +44,93 @@
/* Identify Bison output. */
#define YYBISON 1
+/* Bison version. */
+#define YYBISON_VERSION "2.4.3"
+
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
/* Pure parsers. */
#define YYPURE 0
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
/* Using locations. */
#define YYLSP_NEEDED 0
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 96 "jamgram.y"
+
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "object.h"
+#include "rules.h"
+
+# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+
+# define F0 -1
+# define P0 (PARSE *)0
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+
+
+/* Line 189 of yacc.c */
+#line 114 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -101,6 +185,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -151,119 +236,184 @@
-/* Copy the first part of user declarations. */
-#line 96 "jamgram.y"
-
-#include "jam.h"
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
-#include "lists.h"
-#include "parse.h"
-#include "scan.h"
-#include "compile.h"
-#include "newstr.h"
-#include "rules.h"
-# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+/* Copy the second part of user declarations. */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
-# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
-# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
-# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+/* Line 264 of yacc.c */
+#line 252 "y.tab.c"
+#ifdef short
+# undef short
+#endif
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
#endif
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
#else
-# define YYERROR_VERBOSE 0
+typedef unsigned short int yytype_uint16;
#endif
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
#endif
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-/* Copy the second part of user declarations. */
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
-/* Line 214 of yacc.c. */
-#line 223 "y.tab.c"
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
-#if ! defined (yyoverflow) || YYERROR_VERBOSE
+#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
-# if YYSTACK_USE_ALLOCA
-# define YYSTACK_ALLOC alloca
-# else
-# ifndef YYSTACK_USE_ALLOCA
-# if defined (alloca) || defined (_ALLOCA_H)
-# define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
# else
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
# endif
# endif
# endif
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
# else
-# if defined (__STDC__) || defined (__cplusplus)
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
# endif
-# define YYSTACK_ALLOC malloc
-# define YYSTACK_FREE free
# endif
-#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-#if (! defined (yyoverflow) \
- && (! defined (__cplusplus) \
- || (YYSTYPE_IS_TRIVIAL)))
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- short yyss;
- YYSTYPE yyvs;
- };
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -271,24 +421,24 @@ union yyalloc
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
-# if 1 < __GNUC__
+# if defined __GNUC__ && 1 < __GNUC__
# define YYCOPY(To, From, Count) \
__builtin_memcpy (To, From, (Count) * sizeof (*(From)))
# else
# define YYCOPY(To, From, Count) \
do \
{ \
- register YYSIZE_T yyi; \
+ YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} \
- while (0)
+ while (YYID (0))
# endif
# endif
@@ -297,48 +447,42 @@ union yyalloc
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack) \
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
- while (0)
-
-#endif
+ while (YYID (0))
-#if defined (__STDC__) || defined (__cplusplus)
- typedef signed char yysigned_char;
-#else
- typedef short yysigned_char;
#endif
-/* YYFINAL -- State number of the termination state. */
+/* YYFINAL -- State number of the termination state. */
#define YYFINAL 43
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 261
+#define YYLAST 243
-/* YYNTOKENS -- Number of terminals. */
+/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 49
-/* YYNNTS -- Number of nonterminals. */
+/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 24
-/* YYNRULES -- Number of rules. */
+/* YYNRULES -- Number of rules. */
#define YYNRULES 75
-/* YYNRULES -- Number of states. */
+/* YYNRULES -- Number of states. */
#define YYNSTATES 159
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
#define YYMAXUTOK 303
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const unsigned char yytranslate[] =
+static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -376,7 +520,7 @@ static const unsigned char yytranslate[] =
#if YYDEBUG
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
YYRHS. */
-static const unsigned char yyprhs[] =
+static const yytype_uint8 yyprhs[] =
{
0, 0, 3, 4, 6, 8, 10, 12, 15, 21,
22, 25, 27, 31, 32, 34, 35, 39, 43, 47,
@@ -388,8 +532,8 @@ static const unsigned char yyprhs[] =
244, 246, 248, 250, 252, 253
};
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yysigned_char yyrhs[] =
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
{
50, 0, -1, -1, 52, -1, 53, -1, 52, -1,
57, -1, 57, 52, -1, 32, 65, 54, 11, 51,
@@ -413,14 +557,14 @@ static const yysigned_char yyrhs[] =
7, 61, 8, -1, -1, 63, 62, -1, 22, 47,
10, 51, -1, 65, -1, 65, 10, 64, -1, 66,
-1, -1, 66, 67, -1, 47, -1, -1, 18, 68,
- 69, 19, -1, 67, 64, -1, 34, 67, 67, 64,
+ 69, 19, -1, 47, 64, -1, 34, 67, 47, 64,
-1, 34, 67, 37, 65, -1, -1, 70, 71, -1,
41, -1, 40, -1, 29, -1, 36, -1, 35, -1,
26, -1, -1, 21, 65, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const unsigned short yyrline[] =
+static const yytype_uint16 yyrline[] =
{
0, 139, 139, 141, 152, 154, 158, 160, 162, 167,
170, 172, 176, 179, 182, 185, 188, 190, 192, 194,
@@ -433,9 +577,9 @@ static const unsigned short yyrline[] =
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
"$end", "error", "$undefined", "_BANG_t", "_BANG_EQUALS_t", "_AMPER_t",
@@ -448,15 +592,15 @@ static const char *const yytname[] =
"RULE_t", "SWITCH_t", "TOGETHER_t", "UPDATED_t", "WHILE_t", "_LBRACE_t",
"_BAR_t", "_BARBAR_t", "_RBRACE_t", "ARG", "STRING", "$accept", "run",
"block", "rules", "null", "assign_list_opt", "arglist_opt", "local_opt",
- "rule", "@1", "@2", "assign", "expr", "cases", "case", "lol", "list",
- "listp", "arg", "@3", "func", "eflags", "eflag", "bindlist", 0
+ "rule", "$@1", "$@2", "assign", "expr", "cases", "case", "lol", "list",
+ "listp", "arg", "$@3", "func", "eflags", "eflag", "bindlist", 0
};
#endif
# ifdef YYPRINT
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
token YYLEX-NUM. */
-static const unsigned short yytoknum[] =
+static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
@@ -467,7 +611,7 @@ static const unsigned short yytoknum[] =
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const unsigned char yyr1[] =
+static const yytype_uint8 yyr1[] =
{
0, 49, 50, 50, 51, 51, 52, 52, 52, 53,
54, 54, 55, 55, 56, 56, 57, 57, 57, 57,
@@ -480,7 +624,7 @@ static const unsigned char yyr1[] =
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const unsigned char yyr2[] =
+static const yytype_uint8 yyr2[] =
{
0, 2, 0, 1, 1, 1, 1, 2, 5, 0,
2, 1, 3, 0, 1, 0, 3, 3, 3, 4,
@@ -495,7 +639,7 @@ static const unsigned char yyr2[] =
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
-static const unsigned char yydefact[] =
+static const yytype_uint8 yydefact[] =
{
2, 61, 66, 58, 15, 0, 58, 58, 58, 0,
58, 58, 0, 9, 60, 0, 3, 0, 6, 0,
@@ -515,8 +659,8 @@ static const unsigned char yydefact[] =
12, 20, 32, 0, 28, 54, 0, 22, 33
};
-/* YYDEFGOTO[NTERM-NUM]. */
-static const short yydefgoto[] =
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
{
-1, 15, 39, 40, 41, 84, 125, 17, 18, 146,
156, 51, 30, 121, 122, 22, 23, 24, 31, 20,
@@ -526,31 +670,31 @@ static const short yydefgoto[] =
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
#define YYPACT_NINF -48
-static const short yypact[] =
+static const yytype_int16 yypact[] =
{
- 179, -48, -48, -48, -15, 7, -48, -16, -48, 3,
- -48, -48, 7, 179, 1, 27, -48, -9, 179, 19,
- -3, 33, -11, 24, 3, -48, -10, 7, 7, -48,
- 138, 9, 30, 35, 13, 205, 53, 22, 151, 20,
- -48, -48, 56, -48, 23, -48, -48, -48, -48, 61,
- -48, -48, 3, -48, 62, -48, -48, -48, -48, -48,
- -48, 58, -48, 179, -48, -48, 52, -48, 164, 7,
- 7, 7, 7, 7, 7, 7, 7, 179, 7, 7,
- -48, -48, -48, -48, 72, 179, -48, -48, 68, 179,
- -48, -48, 85, -48, 77, 73, 8, -48, -48, -48,
- 50, 57, -48, -48, -48, 45, 93, 93, -48, -48,
- 45, -48, -48, 64, 245, 245, -48, -48, 179, 66,
- 67, 69, 68, 71, -48, 205, -48, -48, -48, -48,
- -48, -48, -48, 70, 79, -48, -48, 109, -48, -48,
- -48, 112, -48, 115, -48, -48, 75, 179, 205, 179,
- -48, -48, -48, 81, -48, -48, 82, -48, -48
+ 170, -48, -48, -48, -12, 7, -48, -17, -48, -3,
+ -48, -48, 7, 170, 1, 22, -48, -9, 170, 19,
+ -2, 79, -6, 29, -3, -48, 2, 7, 7, -48,
+ 138, 20, 44, 45, 18, 196, 51, 26, 151, 24,
+ -48, -48, 62, -48, 27, -48, -48, -48, -48, 61,
+ -48, -48, -3, -48, 67, -48, -48, -48, -48, -48,
+ -48, 58, -48, 170, -48, -48, 50, -48, 52, 7,
+ 7, 7, 7, 7, 7, 7, 7, 170, 7, 7,
+ -48, -48, -48, -48, 70, 170, -48, -48, 87, 170,
+ -48, -48, 94, -48, 17, 99, -20, -48, -48, -48,
+ 69, 71, -48, -48, -48, 91, 156, 156, -48, -48,
+ 91, -48, -48, 77, 78, 78, -48, -48, 170, 81,
+ 66, 82, 87, 95, -48, 196, -48, -48, -48, -48,
+ -48, -48, -48, 97, 112, -48, -48, 135, -48, -48,
+ -48, 150, -48, 148, -48, -48, 98, 170, 196, 170,
+ -48, -48, -48, 115, -48, -48, 116, -48, -48
};
/* YYPGOTO[NTERM-NUM]. */
-static const short yypgoto[] =
+static const yytype_int16 yypgoto[] =
{
- -48, -48, -47, 5, 104, -48, -48, 136, -27, -48,
- -48, 47, 60, 36, -48, -13, -4, -48, 0, -48,
+ -48, -48, -47, 5, 140, -48, -48, 171, -27, -48,
+ -48, 80, 60, 54, -48, -13, -4, -48, 0, -48,
-48, -48, -48, -48
};
@@ -559,106 +703,86 @@ static const short yypgoto[] =
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -59
-static const short yytable[] =
+static const yytype_int16 yytable[] =
{
19, 42, 32, 33, 34, 16, 36, 37, 86, 35,
- 27, -58, -58, 19, 28, 1, 101, 25, 19, -58,
- 53, 1, -14, 45, 65, 1, 1, 43, 46, 44,
- 113, 52, 63, 47, 64, 19, 48, 66, 119, 80,
- 97, 81, 123, 49, 29, 128, 94, 95, -58, 82,
- 29, 102, 96, 50, 29, 29, 85, 72, 73, 55,
- 75, 76, 56, 19, 87, 88, 90, 91, 57, 58,
- 92, 135, 38, 59, 60, 93, 116, 19, 117, 99,
- 61, 98, 103, 118, 127, 19, 46, 67, 68, 19,
- 120, 47, 124, 131, 48, 130, 129, 69, 142, 133,
- 153, 49, 155, 132, 148, 72, 73, 74, 75, 76,
- 134, 141, 136, 147, 137, 138, 145, 140, 19, 149,
- 150, 154, 143, 152, 144, 19, 151, 157, 158, 105,
- 106, 107, 108, 109, 110, 111, 112, 83, 114, 115,
- 26, 126, 69, 70, 71, 0, 0, 19, 19, 19,
- 72, 73, 74, 75, 76, 69, 70, 71, 139, 0,
- 0, 0, 0, 72, 73, 74, 75, 76, 69, 70,
- 71, 0, 104, 0, 0, 0, 72, 73, 74, 75,
- 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 89, 78, 79, 1, 0, 2,
- 0, 0, 3, 0, 0, 0, 4, 5, 78, 79,
- 6, 7, 8, 9, 0, 0, 10, -15, 11, 0,
- 0, 12, 13, 1, 0, 2, 14, 0, 3, 0,
- 0, 0, 4, 5, 0, 0, 6, 25, 8, 9,
- 0, 0, 10, 0, 11, 0, 0, 12, 13, 69,
- 70, 71, 14, 0, 0, 0, 0, 72, 73, 74,
- 75, 76
+ 27, -58, -58, 19, 28, 1, 101, 128, 19, -58,
+ 25, -14, 43, 45, 65, 1, 46, 129, 46, 44,
+ 113, 47, 52, 47, 48, 19, 48, 63, 119, 64,
+ 97, 49, 123, 49, 29, 53, 94, 95, -58, 66,
+ 80, 102, 96, 50, 29, 81, 69, 70, 71, 82,
+ 104, 85, 87, 19, 72, 73, 74, 75, 76, 88,
+ 90, 135, 38, 91, 92, 93, 116, 19, 117, 99,
+ 103, 118, 69, 70, 71, 19, 98, 67, 68, 19,
+ 72, 73, 74, 75, 76, 130, 78, 79, 142, 133,
+ 153, 124, 155, 72, 73, 55, 75, 76, 56, 120,
+ 127, 141, 131, 137, 57, 58, 145, 132, 19, 59,
+ 60, 154, 143, 134, 144, 19, 61, 136, 138, 105,
+ 106, 107, 108, 109, 110, 111, 112, 148, 114, 115,
+ 147, 140, 69, 70, 71, 149, 152, 19, 19, 19,
+ 72, 73, 74, 75, 76, 69, 70, 71, 150, 151,
+ 69, 157, 158, 72, 73, 74, 75, 76, 72, 73,
+ 74, 75, 76, 83, 126, 26, 139, 0, 0, 0,
+ 0, 77, 78, 79, 0, 0, 0, 0, 1, 0,
+ 2, 0, 0, 3, 89, 78, 79, 4, 5, 0,
+ 0, 6, 7, 8, 9, 0, 0, 10, -15, 11,
+ 0, 0, 12, 13, 1, 0, 2, 14, 0, 3,
+ 0, 0, 0, 4, 5, 0, 0, 6, 25, 8,
+ 9, 0, 0, 10, 0, 11, 0, 0, 12, 13,
+ 0, 0, 0, 14
};
-static const short yycheck[] =
+static const yytype_int16 yycheck[] =
{
0, 14, 6, 7, 8, 0, 10, 11, 35, 9,
- 3, 10, 11, 13, 7, 18, 63, 32, 18, 18,
- 20, 18, 38, 18, 24, 18, 18, 0, 9, 38,
- 77, 34, 43, 14, 10, 35, 17, 47, 85, 30,
- 53, 11, 89, 24, 47, 37, 50, 51, 47, 14,
- 47, 64, 52, 34, 47, 47, 43, 12, 13, 26,
- 15, 16, 29, 63, 11, 43, 46, 11, 35, 36,
- 47, 118, 12, 40, 41, 14, 80, 77, 82, 21,
- 47, 19, 30, 11, 11, 85, 9, 27, 28, 89,
- 22, 14, 7, 43, 17, 99, 96, 4, 125, 103,
- 147, 24, 149, 46, 25, 12, 13, 14, 15, 16,
- 46, 124, 46, 43, 47, 46, 129, 46, 118, 10,
- 8, 148, 126, 48, 128, 125, 11, 46, 46, 69,
- 70, 71, 72, 73, 74, 75, 76, 33, 78, 79,
- 4, 94, 4, 5, 6, -1, -1, 147, 148, 149,
- 12, 13, 14, 15, 16, 4, 5, 6, 122, -1,
- -1, -1, -1, 12, 13, 14, 15, 16, 4, 5,
- 6, -1, 8, -1, -1, -1, 12, 13, 14, 15,
- 16, 43, 44, 45, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 43, 44, 45, 18, -1, 20,
- -1, -1, 23, -1, -1, -1, 27, 28, 44, 45,
- 31, 32, 33, 34, -1, -1, 37, 38, 39, -1,
- -1, 42, 43, 18, -1, 20, 47, -1, 23, -1,
- -1, -1, 27, 28, -1, -1, 31, 32, 33, 34,
- -1, -1, 37, -1, 39, -1, -1, 42, 43, 4,
- 5, 6, 47, -1, -1, -1, -1, 12, 13, 14,
- 15, 16
+ 3, 10, 11, 13, 7, 18, 63, 37, 18, 18,
+ 32, 38, 0, 18, 24, 18, 9, 47, 9, 38,
+ 77, 14, 34, 14, 17, 35, 17, 43, 85, 10,
+ 53, 24, 89, 24, 47, 47, 50, 51, 47, 47,
+ 30, 64, 52, 34, 47, 11, 4, 5, 6, 14,
+ 8, 43, 11, 63, 12, 13, 14, 15, 16, 43,
+ 46, 118, 12, 11, 47, 14, 80, 77, 82, 21,
+ 30, 11, 4, 5, 6, 85, 19, 27, 28, 89,
+ 12, 13, 14, 15, 16, 99, 44, 45, 125, 103,
+ 147, 7, 149, 12, 13, 26, 15, 16, 29, 22,
+ 11, 124, 43, 47, 35, 36, 129, 46, 118, 40,
+ 41, 148, 126, 46, 128, 125, 47, 46, 46, 69,
+ 70, 71, 72, 73, 74, 75, 76, 25, 78, 79,
+ 43, 46, 4, 5, 6, 10, 48, 147, 148, 149,
+ 12, 13, 14, 15, 16, 4, 5, 6, 8, 11,
+ 4, 46, 46, 12, 13, 14, 15, 16, 12, 13,
+ 14, 15, 16, 33, 94, 4, 122, -1, -1, -1,
+ -1, 43, 44, 45, -1, -1, -1, -1, 18, -1,
+ 20, -1, -1, 23, 43, 44, 45, 27, 28, -1,
+ -1, 31, 32, 33, 34, -1, -1, 37, 38, 39,
+ -1, -1, 42, 43, 18, -1, 20, 47, -1, 23,
+ -1, -1, -1, 27, 28, -1, -1, 31, 32, 33,
+ 34, -1, -1, 37, -1, 39, -1, -1, 42, 43,
+ -1, -1, -1, 47
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
-static const unsigned char yystos[] =
+static const yytype_uint8 yystos[] =
{
0, 18, 20, 23, 27, 28, 31, 32, 33, 34,
37, 39, 42, 43, 47, 50, 52, 56, 57, 67,
68, 70, 64, 65, 66, 32, 56, 3, 7, 47,
61, 67, 65, 65, 65, 67, 65, 65, 61, 51,
52, 53, 64, 0, 38, 52, 9, 14, 17, 24,
- 34, 60, 34, 67, 69, 26, 29, 35, 36, 40,
+ 34, 60, 34, 47, 69, 26, 29, 35, 36, 40,
41, 47, 71, 43, 10, 67, 47, 61, 61, 4,
5, 6, 12, 13, 14, 15, 16, 43, 44, 45,
30, 11, 14, 53, 54, 43, 57, 11, 43, 43,
46, 11, 47, 14, 65, 65, 67, 64, 19, 21,
72, 51, 64, 30, 8, 61, 61, 61, 61, 61,
61, 61, 61, 51, 61, 61, 65, 65, 11, 51,
- 22, 62, 63, 51, 7, 55, 60, 11, 37, 67,
+ 22, 62, 63, 51, 7, 55, 60, 11, 37, 47,
65, 43, 46, 65, 46, 51, 46, 47, 46, 62,
46, 64, 57, 65, 65, 64, 58, 43, 25, 10,
8, 11, 48, 51, 57, 51, 59, 46, 46
};
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY (-2)
@@ -666,13 +790,23 @@ static const unsigned char yystos[] =
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
+#define YYERROR goto yyerrorlab
+
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -683,30 +817,63 @@ do \
yychar = (Token); \
yylval = (Value); \
yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK; \
+ YYPOPSTACK (1); \
goto yybackup; \
} \
else \
- { \
- yyerror ("syntax error: cannot back up");\
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
-while (0)
+while (YYID (0))
+
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
- are run). */
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- Current.first_line = Rhs[1].first_line; \
- Current.first_column = Rhs[1].first_column; \
- Current.last_line = Rhs[N].last_line; \
- Current.last_column = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
#endif
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
/* YYLEX -- calling `yylex' with the right arguments. */
#ifdef YYLEX_PARAM
@@ -727,43 +894,100 @@ while (0)
do { \
if (yydebug) \
YYFPRINTF Args; \
-} while (0)
+} while (YYID (0))
-# define YYDSYMPRINT(Args) \
-do { \
- if (yydebug) \
- yysymprint Args; \
-} while (0)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
-# define YYDSYMPRINTF(Title, Token, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yysymprint (stderr, \
- Token, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (0)
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded). |
+| TOP (included). |
`------------------------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
#else
static void
-yy_stack_print (bottom, top)
- short *bottom;
- short *top;
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (/* Nothing. */; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
YYFPRINTF (stderr, "\n");
}
@@ -771,45 +995,52 @@ yy_stack_print (bottom, top)
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
-} while (0)
+} while (YYID (0))
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_reduce_print (int yyrule)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
#else
static void
-yy_reduce_print (yyrule)
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
int yyrule;
#endif
{
+ int yynrhs = yyr2[yyrule];
int yyi;
- unsigned int yylineno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
- yyrule - 1, yylineno);
- /* Print the symbols being reduced, and their result. */
- for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
- YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
- YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
}
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
- yy_reduce_print (Rule); \
-} while (0)
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
# define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
# define YY_STACK_PRINT(Bottom, Top)
# define YY_REDUCE_PRINT(Rule)
#endif /* !YYDEBUG */
@@ -824,13 +1055,9 @@ int yydebug;
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
- SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
@@ -840,45 +1067,47 @@ int yydebug;
#if YYERROR_VERBOSE
# ifndef yystrlen
-# if defined (__GLIBC__) && defined (_STRING_H)
+# if defined __GLIBC__ && defined _STRING_H
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
-# if defined (__STDC__) || defined (__cplusplus)
yystrlen (const char *yystr)
-# else
+#else
+static YYSIZE_T
yystrlen (yystr)
- const char *yystr;
-# endif
+ const char *yystr;
+#endif
{
- register const char *yys = yystr;
-
- while (*yys++ != '\0')
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
continue;
-
- return yys - yystr - 1;
+ return yylen;
}
# endif
# endif
# ifndef yystpcpy
-# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static char *
-# if defined (__STDC__) || defined (__cplusplus)
yystpcpy (char *yydest, const char *yysrc)
-# else
+#else
+static char *
yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-# endif
+ char *yydest;
+ const char *yysrc;
+#endif
{
- register char *yyd = yydest;
- register const char *yys = yysrc;
+ char *yyd = yydest;
+ const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
@@ -888,84 +1117,204 @@ yystpcpy (yydest, yysrc)
# endif
# endif
-#endif /* !YYERROR_VERBOSE */
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
-
+ if (! yyres)
+ return yystrlen (yystr);
-#if YYDEBUG
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yysymprint (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ int yyn = yypact[yystate];
- if (yytype < YYNTOKENS)
- {
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- switch (yytype)
{
- default:
- break;
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
}
- YYFPRINTF (yyoutput, ")");
}
+#endif /* YYERROR_VERBOSE */
+
-#endif /* ! YYDEBUG */
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
#else
static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
int yytype;
YYSTYPE *yyvaluep;
#endif
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
switch (yytype)
{
default:
- break;
+ break;
}
}
-
/* Prevent warnings from -Wmissing-prototypes. */
-
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
-# else
+#else
int yyparse ();
-# endif
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
@@ -973,7 +1322,6 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-
/* The lookahead symbol. */
int yychar;
@@ -985,19 +1333,23 @@ int yynerrs;
-/*----------.
-| yyparse. |
-`----------*/
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void *YYPARSE_PARAM)
-# else
-int yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-# endif
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
int
yyparse (void)
#else
@@ -1008,59 +1360,67 @@ yyparse ()
#endif
{
- register int yystate;
- register int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken = 0;
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
- /* The state stack. */
- short yyssa[YYINITDEPTH];
- short *yyss = yyssa;
- register short *yyssp;
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- register YYSTYPE *yyvsp;
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
-#define YYPOPSTACK (yyvsp--, yyssp--)
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
- YYSIZE_T yystacksize = YYINITDEPTH;
+ YYSIZE_T yystacksize;
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
- /* When reducing, the number of symbols on the RHS of the reduced
- rule. */
- int yylen;
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
-
yyssp = yyss;
yyvsp = yyvs;
@@ -1071,8 +1431,7 @@ yyparse ()
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks.
- */
+ have just been pushed. So pushing a state here evens the stacks. */
yyssp++;
yysetstate:
@@ -1085,21 +1444,19 @@ yyparse ()
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
+ /* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-
+ yytype_int16 *yyss1 = yyss;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
- yyoverflow ("parser stack overflow",
+ yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
-
&yystacksize);
yyss = yyss1;
@@ -1107,24 +1464,23 @@ yyparse ()
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
- goto yyoverflowlab;
+ goto yyexhaustedlab;
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyoverflowlab;
+ goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
{
- short *yyss1 = yyss;
+ yytype_int16 *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
- goto yyoverflowlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1135,7 +1491,6 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
-
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1145,6 +1500,9 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
goto yybackup;
/*-----------.
@@ -1152,12 +1510,10 @@ yyparse ()
`-----------*/
yybackup:
-/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
-/* yyresume: */
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
/* First try to decide what to do without reference to lookahead token. */
-
yyn = yypact[yystate];
if (yyn == YYPACT_NINF)
goto yydefault;
@@ -1179,7 +1535,7 @@ yybackup:
else
{
yytoken = YYTRANSLATE (yychar);
- YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
/* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1196,25 +1552,20 @@ yybackup:
goto yyreduce;
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Shift the lookahead token. */
- YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
-
- /* Discard the token being shifted unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- *++yyvsp = yylval;
-
-
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
yystate = yyn;
+ *++yyvsp = yylval;
+
goto yynewstate;
@@ -1250,385 +1601,530 @@ yyreduce:
switch (yyn)
{
case 3:
+
+/* Line 1464 of yacc.c */
#line 142 "jamgram.y"
- { parse_save( yyvsp[0].parse ); }
+ { parse_save( (yyvsp[(1) - (1)]).parse ); }
break;
case 4:
+
+/* Line 1464 of yacc.c */
#line 153 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 5:
+
+/* Line 1464 of yacc.c */
#line 155 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 6:
+
+/* Line 1464 of yacc.c */
#line 159 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 7:
+
+/* Line 1464 of yacc.c */
#line 161 "jamgram.y"
- { yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = prules( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 8:
+
+/* Line 1464 of yacc.c */
#line 163 "jamgram.y"
- { yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = plocal( (yyvsp[(2) - (5)]).parse, (yyvsp[(3) - (5)]).parse, (yyvsp[(5) - (5)]).parse ); }
break;
case 9:
+
+/* Line 1464 of yacc.c */
#line 167 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 10:
+
+/* Line 1464 of yacc.c */
#line 171 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_SET; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; (yyval).number = ASSIGN_SET; }
break;
case 11:
+
+/* Line 1464 of yacc.c */
#line 173 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_APPEND; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; (yyval).number = ASSIGN_APPEND; }
break;
case 12:
+
+/* Line 1464 of yacc.c */
#line 177 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 13:
+
+/* Line 1464 of yacc.c */
#line 179 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 14:
+
+/* Line 1464 of yacc.c */
#line 183 "jamgram.y"
- { yyval.number = 1; }
+ { (yyval).number = 1; }
break;
case 15:
+
+/* Line 1464 of yacc.c */
#line 185 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 16:
+
+/* Line 1464 of yacc.c */
#line 189 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 17:
+
+/* Line 1464 of yacc.c */
#line 191 "jamgram.y"
- { yyval.parse = pincl( yyvsp[-1].parse ); }
+ { (yyval).parse = pincl( (yyvsp[(2) - (3)]).parse ); }
break;
case 18:
+
+/* Line 1464 of yacc.c */
#line 193 "jamgram.y"
- { yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (3)]).string, (yyvsp[(2) - (3)]).parse ); }
break;
case 19:
+
+/* Line 1464 of yacc.c */
#line 195 "jamgram.y"
- { yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset( (yyvsp[(1) - (4)]).parse, (yyvsp[(3) - (4)]).parse, (yyvsp[(2) - (4)]).number ); }
break;
case 20:
+
+/* Line 1464 of yacc.c */
#line 197 "jamgram.y"
- { yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset1( (yyvsp[(1) - (6)]).parse, (yyvsp[(3) - (6)]).parse, (yyvsp[(5) - (6)]).parse, (yyvsp[(4) - (6)]).number ); }
break;
case 21:
+
+/* Line 1464 of yacc.c */
#line 199 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 22:
+
+/* Line 1464 of yacc.c */
#line 201 "jamgram.y"
- { yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-6].number ); }
+ { (yyval).parse = pfor( (yyvsp[(3) - (8)]).string, (yyvsp[(5) - (8)]).parse, (yyvsp[(7) - (8)]).parse, (yyvsp[(2) - (8)]).number ); }
break;
case 23:
+
+/* Line 1464 of yacc.c */
#line 203 "jamgram.y"
- { yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pswitch( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 24:
+
+/* Line 1464 of yacc.c */
#line 205 "jamgram.y"
- { yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse, pnull() ); }
break;
case 25:
+
+/* Line 1464 of yacc.c */
#line 207 "jamgram.y"
- { yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pmodule( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 26:
+
+/* Line 1464 of yacc.c */
#line 209 "jamgram.y"
- { yyval.parse = pclass( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pclass( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 27:
+
+/* Line 1464 of yacc.c */
#line 211 "jamgram.y"
- { yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pwhile( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 28:
+
+/* Line 1464 of yacc.c */
#line 213 "jamgram.y"
- { yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (7)]).parse, (yyvsp[(4) - (7)]).parse, (yyvsp[(7) - (7)]).parse ); }
break;
case 29:
+
+/* Line 1464 of yacc.c */
#line 215 "jamgram.y"
- { yyval.parse = psetc( yyvsp[-2].string, yyvsp[0].parse, yyvsp[-1].parse, yyvsp[-4].number ); }
+ { (yyval).parse = psetc( (yyvsp[(3) - (5)]).string, (yyvsp[(5) - (5)]).parse, (yyvsp[(4) - (5)]).parse, (yyvsp[(1) - (5)]).number ); }
break;
case 30:
+
+/* Line 1464 of yacc.c */
#line 217 "jamgram.y"
- { yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 31:
+
+/* Line 1464 of yacc.c */
#line 219 "jamgram.y"
{ yymode( SCAN_STRING ); }
break;
case 32:
+
+/* Line 1464 of yacc.c */
#line 221 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 33:
+
+/* Line 1464 of yacc.c */
#line 223 "jamgram.y"
- { yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); }
+ { (yyval).parse = psete( (yyvsp[(3) - (9)]).string,(yyvsp[(4) - (9)]).parse,(yyvsp[(7) - (9)]).string,(yyvsp[(2) - (9)]).number ); }
break;
case 34:
+
+/* Line 1464 of yacc.c */
#line 231 "jamgram.y"
- { yyval.number = ASSIGN_SET; }
+ { (yyval).number = ASSIGN_SET; }
break;
case 35:
+
+/* Line 1464 of yacc.c */
#line 233 "jamgram.y"
- { yyval.number = ASSIGN_APPEND; }
+ { (yyval).number = ASSIGN_APPEND; }
break;
case 36:
+
+/* Line 1464 of yacc.c */
#line 235 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 37:
+
+/* Line 1464 of yacc.c */
#line 237 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 38:
+
+/* Line 1464 of yacc.c */
#line 244 "jamgram.y"
- { yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_EXISTS, (yyvsp[(1) - (1)]).parse, pnull() ); }
break;
case 39:
+
+/* Line 1464 of yacc.c */
#line 246 "jamgram.y"
- { yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_EQUALS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 40:
+
+/* Line 1464 of yacc.c */
#line 248 "jamgram.y"
- { yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_NOTEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 41:
+
+/* Line 1464 of yacc.c */
#line 250 "jamgram.y"
- { yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 42:
+
+/* Line 1464 of yacc.c */
#line 252 "jamgram.y"
- { yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESSEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 43:
+
+/* Line 1464 of yacc.c */
#line 254 "jamgram.y"
- { yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MORE, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 44:
+
+/* Line 1464 of yacc.c */
#line 256 "jamgram.y"
- { yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MOREEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 45:
+
+/* Line 1464 of yacc.c */
#line 258 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 46:
+
+/* Line 1464 of yacc.c */
#line 260 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 47:
+
+/* Line 1464 of yacc.c */
#line 262 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 48:
+
+/* Line 1464 of yacc.c */
#line 264 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 49:
+
+/* Line 1464 of yacc.c */
#line 266 "jamgram.y"
- { yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_IN, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 50:
+
+/* Line 1464 of yacc.c */
#line 268 "jamgram.y"
- { yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_NOT, (yyvsp[(2) - (2)]).parse, pnull() ); }
break;
case 51:
+
+/* Line 1464 of yacc.c */
#line 270 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 52:
+
+/* Line 1464 of yacc.c */
#line 281 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 53:
+
+/* Line 1464 of yacc.c */
#line 283 "jamgram.y"
- { yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 54:
+
+/* Line 1464 of yacc.c */
#line 287 "jamgram.y"
- { yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
+ { (yyval).parse = psnode( (yyvsp[(2) - (4)]).string, (yyvsp[(4) - (4)]).parse ); }
break;
case 55:
+
+/* Line 1464 of yacc.c */
#line 296 "jamgram.y"
- { yyval.parse = pnode( P0, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( P0, (yyvsp[(1) - (1)]).parse ); }
break;
case 56:
+
+/* Line 1464 of yacc.c */
#line 298 "jamgram.y"
- { yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(3) - (3)]).parse, (yyvsp[(1) - (3)]).parse ); }
break;
case 57:
+
+/* Line 1464 of yacc.c */
#line 308 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; yymode( SCAN_NORMAL ); }
break;
case 58:
+
+/* Line 1464 of yacc.c */
#line 312 "jamgram.y"
- { yyval.parse = pnull(); yymode( SCAN_PUNCT ); }
+ { (yyval).parse = pnull(); yymode( SCAN_PUNCT ); }
break;
case 59:
+
+/* Line 1464 of yacc.c */
#line 314 "jamgram.y"
- { yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pappend( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 60:
+
+/* Line 1464 of yacc.c */
#line 318 "jamgram.y"
- { yyval.parse = plist( yyvsp[0].string ); }
+ { (yyval).parse = plist( (yyvsp[(1) - (1)]).string ); }
break;
case 61:
+
+/* Line 1464 of yacc.c */
#line 319 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 62:
+
+/* Line 1464 of yacc.c */
#line 320 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(3) - (4)]).parse; }
break;
case 63:
+
+/* Line 1464 of yacc.c */
#line 329 "jamgram.y"
- { yyval.parse = prule( yyvsp[-1].string, yyvsp[0].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (2)]).string, (yyvsp[(2) - (2)]).parse ); }
break;
case 64:
+
+/* Line 1464 of yacc.c */
#line 331 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].string, yyvsp[0].parse ) ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, prule( (yyvsp[(3) - (4)]).string, (yyvsp[(4) - (4)]).parse ) ); }
break;
case 65:
+
+/* Line 1464 of yacc.c */
#line 333 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, (yyvsp[(4) - (4)]).parse ); }
break;
case 66:
+
+/* Line 1464 of yacc.c */
#line 343 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 67:
+
+/* Line 1464 of yacc.c */
#line 345 "jamgram.y"
- { yyval.number = yyvsp[-1].number | yyvsp[0].number; }
+ { (yyval).number = (yyvsp[(1) - (2)]).number | (yyvsp[(2) - (2)]).number; }
break;
case 68:
+
+/* Line 1464 of yacc.c */
#line 349 "jamgram.y"
- { yyval.number = EXEC_UPDATED; }
+ { (yyval).number = EXEC_UPDATED; }
break;
case 69:
+
+/* Line 1464 of yacc.c */
#line 351 "jamgram.y"
- { yyval.number = EXEC_TOGETHER; }
+ { (yyval).number = EXEC_TOGETHER; }
break;
case 70:
+
+/* Line 1464 of yacc.c */
#line 353 "jamgram.y"
- { yyval.number = EXEC_IGNORE; }
+ { (yyval).number = EXEC_IGNORE; }
break;
case 71:
+
+/* Line 1464 of yacc.c */
#line 355 "jamgram.y"
- { yyval.number = EXEC_QUIETLY; }
+ { (yyval).number = EXEC_QUIETLY; }
break;
case 72:
+
+/* Line 1464 of yacc.c */
#line 357 "jamgram.y"
- { yyval.number = EXEC_PIECEMEAL; }
+ { (yyval).number = EXEC_PIECEMEAL; }
break;
case 73:
+
+/* Line 1464 of yacc.c */
#line 359 "jamgram.y"
- { yyval.number = EXEC_EXISTING; }
+ { (yyval).number = EXEC_EXISTING; }
break;
case 74:
+
+/* Line 1464 of yacc.c */
#line 368 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 75:
+
+/* Line 1464 of yacc.c */
#line 370 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; }
break;
- }
-
-/* Line 991 of yacc.c. */
-#line 1621 "y.tab.c"
-
- yyvsp -= yylen;
- yyssp -= yylen;
+/* Line 1464 of yacc.c */
+#line 2118 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+ YYPOPSTACK (yylen);
+ yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
-
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -1652,54 +2148,41 @@ yyerrlab:
if (!yyerrstatus)
{
++yynerrs;
-#if YYERROR_VERBOSE
- yyn = yypact[yystate];
-
- if (YYPACT_NINF < yyn && yyn < YYLAST)
- {
- YYSIZE_T yysize = 0;
- int yytype = YYTRANSLATE (yychar);
- char *yymsg;
- int yyx, yycount;
-
- yycount = 0;
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- yysize += yystrlen (yytname[yyx]) + 15, yycount++;
- yysize += yystrlen ("syntax error, unexpected ") + 1;
- yysize += yystrlen (yytname[yytype]);
- yymsg = (char *) YYSTACK_ALLOC (yysize);
- if (yymsg != 0)
- {
- char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
- yyp = yystpcpy (yyp, yytname[yytype]);
-
- if (yycount < 5)
- {
- yycount = 0;
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *));
- yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- const char *yyq = ! yycount ? ", expecting " : " or ";
- yyp = yystpcpy (yyp, yyq);
- yyp = yystpcpy (yyp, yytname[yyx]);
- yycount++;
- }
- }
- yyerror (yymsg);
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
- }
- else
- yyerror ("syntax error; also virtual memory exhausted");
- }
- else
-#endif /* YYERROR_VERBOSE */
- yyerror ("syntax error");
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
}
@@ -1709,51 +2192,49 @@ yyerrlab:
/* If just tried and failed to reuse lookahead token after an
error, discard it. */
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- {
- /* Pop the error token. */
- YYPOPSTACK;
- /* Pop the rest of the stack. */
- while (yyss < yyssp)
- {
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[*yyssp], yyvsp);
- YYPOPSTACK;
- }
- YYABORT;
- }
-
- YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
- yydestruct (yytoken, &yylval);
- yychar = YYEMPTY;
-
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
/* Else will try to reuse lookahead token after shifting the error
token. */
- goto yyerrlab2;
+ goto yyerrlab1;
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action. |
-`----------------------------------------------------*/
-yyerrlab1:
-
- /* Suppress GCC warning that yyerrlab1 is unused when no action
- invokes YYERROR. */
-#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
- __attribute__ ((__unused__))
-#endif
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
- goto yyerrlab2;
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
-/*---------------------------------------------------------------.
-| yyerrlab2 -- pop states until the error token can be shifted. |
-`---------------------------------------------------------------*/
-yyerrlab2:
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
yyerrstatus = 3; /* Each real token shifted decrements this. */
for (;;)
@@ -1774,22 +2255,20 @@ yyerrlab2:
if (yyssp == yyss)
YYABORT;
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[yystate], yyvsp);
- yyvsp--;
- yystate = *--yyssp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- YYDPRINTF ((stderr, "Shifting error token, "));
-
*++yyvsp = yylval;
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
yystate = yyn;
goto yynewstate;
@@ -1808,22 +2287,40 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here. |
-`----------------------------------------------*/
-yyoverflowlab:
- yyerror ("parser stack overflow");
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
yyresult = 2;
/* Fall through. */
#endif
yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
- return yyresult;
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
}
diff --git a/tools/build/v2/engine/jamgram.h b/tools/build/v2/engine/jamgram.h
index 3cb7656417..97f117535d 100644
--- a/tools/build/v2/engine/jamgram.h
+++ b/tools/build/v2/engine/jamgram.h
@@ -1,27 +1,36 @@
-/* A Bison parser, made by GNU Bison 1.875. */
+/* A Bison parser, made by GNU Bison 2.4.3. */
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -77,6 +86,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -127,14 +137,13 @@
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/tools/build/v2/engine/jamgram.y b/tools/build/v2/engine/jamgram.y
index c26b1e1b6b..543f1561a4 100644
--- a/tools/build/v2/engine/jamgram.y
+++ b/tools/build/v2/engine/jamgram.y
@@ -100,34 +100,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -325,9 +325,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | ON_t arg arg lol
+ | ON_t arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| ON_t arg RETURN_t list
{ $$.parse = pon( $2.parse, $4.parse ); }
@@ -369,3 +369,5 @@ bindlist : /* empty */
| BIND_t list
{ $$.parse = $2.parse; }
;
+
+
diff --git a/tools/build/v2/engine/jamgram.yy b/tools/build/v2/engine/jamgram.yy
index 1524348710..8d20e3896e 100644
--- a/tools/build/v2/engine/jamgram.yy
+++ b/tools/build/v2/engine/jamgram.yy
@@ -56,34 +56,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -281,9 +281,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | `on` arg arg lol
+ | `on` arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| `on` arg `return` list
{ $$.parse = pon( $2.parse, $4.parse ); }
diff --git a/tools/build/v2/engine/lists.c b/tools/build/v2/engine/lists.c
index ebabb63e90..c93fd7c090 100644
--- a/tools/build/v2/engine/lists.c
+++ b/tools/build/v2/engine/lists.c
@@ -5,27 +5,65 @@
*/
# include "jam.h"
-# include "newstr.h"
+# include "object.h"
# include "lists.h"
+# include "assert.h"
/*
- * lists.c - maintain lists of strings
- *
- * This implementation essentially uses a singly linked list, but
- * guarantees that the head element of every list has a valid pointer
- * to the tail of the list, so the new elements can efficiently and
- * properly be appended to the end of a list.
- *
- * To avoid massive allocation, list_free() just tacks the whole freed
- * chain onto freelist and list_new() looks on freelist first for an
- * available list struct. list_free() does not free the strings in the
- * chain: it lazily lets list_new() do so.
+ * lists.c - maintain lists of objects
*
* 08/23/94 (seiwald) - new list_append()
* 09/07/00 (seiwald) - documented lol_*() functions
*/
-static LIST *freelist = 0; /* junkpile for list_free() */
+struct freelist_node { struct freelist_node *next; };
+
+static struct freelist_node *freelist[32]; /* junkpile for list_free() */
+
+static unsigned get_bucket( unsigned size )
+{
+ unsigned bucket = 0;
+ while ( size > ( 1u << bucket ) ) ++bucket;
+ return bucket;
+}
+
+static LIST * list_alloc( unsigned size )
+{
+ unsigned bucket = get_bucket( size );
+ if ( freelist[ bucket ] )
+ {
+ struct freelist_node * result = freelist[ bucket ];
+ freelist[ bucket ] = result->next;
+ return (LIST *)result;
+ }
+ else
+ {
+ return (LIST *)BJAM_MALLOC( sizeof( LIST ) + ( 1u << bucket ) * sizeof( OBJECT * ) );
+ }
+}
+
+static void list_dealloc( LIST * l )
+{
+ unsigned size = list_length( l );
+ unsigned bucket;
+ struct freelist_node * node = (struct freelist_node *)l;
+
+ if ( size == 0 ) return;
+
+ bucket = get_bucket( size );;
+
+#ifdef BJAM_NO_MEM_CACHE
+
+ BJAM_FREE( node );
+
+#else
+
+ node->next = freelist[ bucket ];
+ freelist[ bucket ] = node;
+
+#endif
+
+}
/*
* list_append() - append a list onto another one, returning total
@@ -33,60 +71,104 @@ static LIST *freelist = 0; /* junkpile for list_free() */
LIST * list_append( LIST * l, LIST * nl )
{
- if ( !nl )
+ if ( list_empty( nl ) )
{
/* Just return l */
}
- else if ( !l )
+ else if ( list_empty( l ) )
{
l = nl;
}
else
{
- /* Graft two non-empty lists. */
- l->tail->next = nl;
- l->tail = nl->tail;
+ int l_size = list_length( l );
+ int nl_size = list_length( nl );
+ int size = l_size + nl_size;
+ unsigned bucket;
+ int i;
+
+ bucket = get_bucket( size );
+ /* Do we need to reallocate? */
+ if ( l_size <= ( 1u << (bucket - 1) ) )
+ {
+ LIST * result = list_alloc( size );
+ memcpy( list_begin( result ), list_begin( l ), l_size * sizeof( OBJECT * ) );
+ list_dealloc( l );
+ l = result;
+ }
+
+ l->impl.size = size;
+ memcpy( list_begin( l ) + l_size, list_begin( nl ), nl_size * sizeof( OBJECT * ) );
+ list_dealloc( nl );
+ return l;
}
return l;
}
+LISTITER list_begin( LIST * l )
+{
+ if ( l )
+ return (LISTITER)( (char *)l + sizeof(LIST) );
+ else
+ return 0;
+}
+
+LISTITER list_end( LIST * l )
+{
+ if ( l )
+ return list_begin( l ) + l->impl.size;
+ else
+ return 0;
+}
+
+LIST * list_new( OBJECT * value )
+{
+ LIST * head;
+ if ( freelist[ 0 ] )
+ {
+ struct freelist_node * result = freelist[ 0 ];
+ freelist[ 0 ] = result->next;
+ head = (LIST *)result;
+ }
+ else
+ {
+ head = BJAM_MALLOC( sizeof( LIST * ) + sizeof( OBJECT * ) );
+ }
+
+ head->impl.size = 1;
+ list_begin( head )[ 0 ] = value;
+
+ return head;
+}
+
/*
- * list_new() - tack a string onto the end of a list of strings
+ * list_push_back() - tack a string onto the end of a list of strings
*/
-LIST * list_new( LIST * head, char * string )
+LIST * list_push_back( LIST * head, OBJECT * value )
{
- LIST * l;
+ unsigned int size = list_length( head );
+ unsigned int i;
if ( DEBUG_LISTS )
- printf( "list > %s <\n", string );
+ printf( "list > %s <\n", object_str( value ) );
- /* Get list struct from freelist, if one available. */
- /* Otherwise allocate. */
- /* If from freelist, must free string first */
-
- if ( freelist )
+ /* If the size is a power of 2, reallocate. */
+ if ( size == 0 )
{
- l = freelist;
- freestr( l->string );
- freelist = freelist->next;
+ head = list_alloc( 1 );
}
- else
+ else if ( ( ( size - 1 ) & size ) == 0 )
{
- l = (LIST *)BJAM_MALLOC( sizeof( LIST ) );
+ LIST * l = list_alloc( size + 1 );
+ memcpy( l, head, sizeof( LIST ) + size * sizeof( OBJECT * ) );
+ list_dealloc( head );
+ head = l;
}
- /* If first on chain, head points here. */
- /* If adding to chain, tack us on. */
- /* Tail must point to this new, last element. */
-
- if ( !head ) head = l;
- else head->tail->next = l;
- head->tail = l;
- l->next = 0;
-
- l->string = string;
+ list_begin( head )[ size ] = value;
+ head->impl.size = size + 1;
return head;
}
@@ -96,11 +178,42 @@ LIST * list_new( LIST * head, char * string )
* list_copy() - copy a whole list of strings (nl) onto end of another (l).
*/
-LIST * list_copy( LIST * l, LIST * nl )
+LIST * list_copy( LIST * l )
{
- for ( ; nl; nl = list_next( nl ) )
- l = list_new( l, copystr( nl->string ) );
- return l;
+ int size = list_length( l );
+ int i;
+ LIST * result;
+
+ if ( size == 0 ) return L0;
+
+ result = list_alloc( size );
+ result->impl.size = size;
+ for ( i = 0; i < size; ++i )
+ {
+ list_begin( result )[ i ] = object_copy( list_begin( l )[ i ] );
+ }
+ return result;
+}
+
+
+LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last )
+{
+ if ( first == last )
+ {
+ return L0;
+ }
+ else
+ {
+ int size = last - first;
+ LIST * result = list_alloc( size );
+ LISTITER dest = list_begin( result );
+ result->impl.size = size;
+ for ( ; first != last; ++first, ++dest )
+ {
+ *dest = object_copy( *first );
+ }
+ return result;
+ }
}
@@ -110,19 +223,19 @@ LIST * list_copy( LIST * l, LIST * nl )
LIST * list_sublist( LIST * l, int start, int count )
{
- LIST * nl = 0;
- for ( ; l && start--; l = list_next( l ) );
- for ( ; l && count--; l = list_next( l ) )
- nl = list_new( nl, copystr( l->string ) );
- return nl;
+ int end = start + count;
+ int size = list_length( l );
+ if ( start >= size ) return L0;
+ if ( end > size ) end = size;
+ return list_copy_range( l, list_begin( l ) + start, list_begin( l ) + end );
}
static int str_ptr_compare( void const * va, void const * vb )
{
- char * a = *( (char * *)va );
- char * b = *( (char * *)vb );
- return strcmp(a, b);
+ OBJECT * a = *( (OBJECT * *)va );
+ OBJECT * b = *( (OBJECT * *)vb );
+ return strcmp(object_str(a), object_str(b));
}
@@ -130,29 +243,15 @@ LIST * list_sort( LIST * l )
{
int len;
int ii;
- char * * strings;
- LIST * listp;
- LIST * result = 0;
+ LIST * result;
if ( !l )
return L0;
len = list_length( l );
- strings = (char * *)BJAM_MALLOC( len * sizeof(char*) );
-
- listp = l;
- for ( ii = 0; ii < len; ++ii )
- {
- strings[ ii ] = listp->string;
- listp = listp->next;
- }
-
- qsort( strings, len, sizeof( char * ), str_ptr_compare );
+ result = list_copy( l );
- for ( ii = 0; ii < len; ++ii )
- result = list_append( result, list_new( 0, strings[ ii ] ) );
-
- BJAM_FREE( strings );
+ qsort( list_begin( result ), len, sizeof( OBJECT * ), str_ptr_compare );
return result;
}
@@ -164,11 +263,14 @@ LIST * list_sort( LIST * l )
void list_free( LIST * head )
{
- /* Just tack onto freelist. */
- if ( head )
+ if ( !list_empty( head ) )
{
- head->tail->next = freelist;
- freelist = head;
+ LISTITER iter = list_begin( head ), end = list_end( head );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ object_free( list_item( iter ) );
+ }
+ list_dealloc( head );
}
}
@@ -179,17 +281,79 @@ void list_free( LIST * head )
LIST * list_pop_front( LIST * l )
{
- LIST * result = l->next;
- if ( result )
+ unsigned size = list_length( l );
+ assert( size != 0 );
+ --size;
+ object_free( list_front( l ) );
+
+ if ( size == 0 )
{
- result->tail = l->tail;
- l->next = L0;
- l->tail = l;
+ list_dealloc( l );
+ return L0;
+ }
+ else if ( ( ( size - 1 ) & size ) == 0 )
+ {
+ LIST * nl = list_alloc( size );
+ nl->impl.size = size;
+ memcpy( list_begin( nl ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ list_dealloc( l );
+ return nl;
+ }
+ else
+ {
+ l->impl.size = size;
+ memmove( list_begin( l ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ return l;
+ }
+}
+
+LIST * list_reverse( LIST * l )
+{
+ int size = list_length( l );
+ if ( size == 0 ) return L0;
+ else
+ {
+ LIST * result = list_alloc( size );
+ int i;
+ result->impl.size = size;
+ for ( i = 0; i < size; ++i )
+ {
+ list_begin( result )[ i ] = object_copy( list_begin( l )[ size - i - 1 ] );
+ }
+ return result;
}
- list_free( l );
- return result;
}
+int list_cmp( LIST * t, LIST * s )
+{
+ int status = 0;
+ LISTITER t_it = list_begin( t ), t_end = list_end( t );
+ LISTITER s_it = list_begin( s ), s_end = list_end( s );
+
+ while ( !status && ( t_it != t_end || s_it != s_end ) )
+ {
+ const char *st = t_it != t_end ? object_str( list_item( t_it ) ) : "";
+ const char *ss = s_it != s_end ? object_str( list_item( s_it ) ) : "";
+
+ status = strcmp( st, ss );
+
+ t_it = t_it != t_end ? list_next( t_it ) : t_it;
+ s_it = s_it != s_end ? list_next( s_it ) : s_it;
+ }
+
+ return status;
+}
+
+int list_is_sublist( LIST * sub, LIST * l )
+{
+ LISTITER iter = list_begin( sub ), end = list_end( sub );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ if ( !list_in( l, list_item( iter ) ) )
+ return 0;
+ }
+ return 1;
+}
/*
* list_print() - print a list of strings to stdout
@@ -197,12 +361,14 @@ LIST * list_pop_front( LIST * l )
void list_print( LIST * l )
{
- LIST * p = 0;
- for ( ; l; p = l, l = list_next( l ) )
- if ( p )
- printf( "%s ", p->string );
- if ( p )
- printf( "%s", p->string );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ if ( iter != end )
+ {
+ printf( "%s", object_str( list_item( iter ) ) );
+ iter = list_next( iter );
+ for ( ; iter != end; iter = list_next( iter ) )
+ printf( " %s", object_str( list_item( iter ) ) );
+ }
}
@@ -212,16 +378,18 @@ void list_print( LIST * l )
int list_length( LIST * l )
{
- int n = 0;
- for ( ; l; l = list_next( l ), ++n );
- return n;
+ if ( l )
+ return l->impl.size;
+ else
+ return 0;
}
-int list_in( LIST * l, char * value )
+int list_in( LIST * l, OBJECT * value )
{
- for ( ; l; l = l->next )
- if ( strcmp( l->string, value ) == 0 )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), value ) )
return 1;
return 0;
}
@@ -229,20 +397,38 @@ int list_in( LIST * l, char * value )
LIST * list_unique( LIST * sorted_list )
{
- LIST * result = 0;
- LIST * last_added = 0;
+ LIST * result = L0;
+ OBJECT * last_added = 0;
- for ( ; sorted_list; sorted_list = sorted_list->next )
+ LISTITER iter = list_begin( sorted_list ), end = list_end( sorted_list );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !last_added || strcmp( sorted_list->string, last_added->string ) != 0 )
+ if ( !last_added || !object_equal( list_item( iter ), last_added ) )
{
- result = list_new( result, sorted_list->string );
- last_added = sorted_list;
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
+ last_added = list_item( iter );
}
}
return result;
}
+void list_done()
+{
+ int i;
+ int total = 0;
+ for ( i = 0; i < sizeof( freelist ) / sizeof( freelist[ 0 ] ); ++i )
+ {
+ struct freelist_node *l, *tmp;
+ int bytes;
+ for( l = freelist[ i ]; l; )
+ {
+ tmp = l;
+ l = l->next;
+ BJAM_FREE( tmp );
+ }
+ }
+}
+
/*
* lol_init() - initialize a LOL (list of lists).
@@ -284,7 +470,7 @@ void lol_free( LOL * lol )
LIST * lol_get( LOL * lol, int i )
{
- return i < lol->count ? lol->list[ i ] : 0;
+ return i < lol->count ? lol->list[ i ] : L0;
}
@@ -309,10 +495,11 @@ void lol_print( LOL * lol )
PyObject *list_to_python(LIST *l)
{
PyObject *result = PyList_New(0);
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for (; l; l = l->next)
+ for (; iter != end; iter = list_next( iter ) )
{
- PyObject* s = PyString_FromString(l->string);
+ PyObject* s = PyString_FromString(object_str(list_item(iter)));
PyList_Append(result, s);
Py_DECREF(s);
}
@@ -322,14 +509,14 @@ PyObject *list_to_python(LIST *l)
LIST *list_from_python(PyObject *l)
{
- LIST * result = 0;
+ LIST * result = L0;
Py_ssize_t i, n;
n = PySequence_Size(l);
for (i = 0; i < n; ++i)
{
PyObject *v = PySequence_GetItem(l, i);
- result = list_new (result, newstr (PyString_AsString(v)));
+ result = list_push_back(result, object_new (PyString_AsString(v)));
Py_DECREF(v);
}
diff --git a/tools/build/v2/engine/lists.h b/tools/build/v2/engine/lists.h
index 1dc598274d..bc97261e57 100644
--- a/tools/build/v2/engine/lists.h
+++ b/tools/build/v2/engine/lists.h
@@ -13,23 +13,23 @@
/*
* lists.h - the LIST structure and routines to manipulate them
*
- * The whole of jam relies on lists of strings as a datatype. This
- * module, in conjunction with newstr.c, handles these relatively
+ * The whole of jam relies on lists of objects as a datatype. This
+ * module, in conjunction with object.c, handles these relatively
* efficiently.
*
* Structures defined:
*
- * LIST - list of strings
+ * LIST - list of OBJECTs
* LOL - list of LISTs
*
* External routines:
*
* list_append() - append a list onto another one, returning total
- * list_new() - tack a string onto the end of a list of strings
- * list_copy() - copy a whole list of strings
- * list_sublist() - copy a subset of a list of strings
- * list_free() - free a list of strings
- * list_print() - print a list of strings to stdout
+ * list_new() - tack an object onto the end of a list of objects
+ * list_copy() - copy a whole list of objects
+ * list_sublist() - copy a subset of a list of objects
+ * list_free() - free a list of objects
+ * list_print() - print a list of objects to stdout
* list_length() - return the number of items in the list
*
* lol_init() - initialize a LOL (list of lists)
@@ -45,6 +45,8 @@
#ifndef LISTS_DWA20011022_H
# define LISTS_DWA20011022_H
+#include "object.h"
+
#ifdef HAVE_PYTHON
#include <Python.h>
#endif
@@ -56,11 +58,14 @@
typedef struct _list LIST;
struct _list {
- LIST *next;
- LIST *tail; /* only valid in head node */
- char *string; /* private copy */
+ union {
+ int size;
+ OBJECT *align;
+ } impl;
};
+typedef OBJECT * * LISTITER;
+
/*
* LOL - list of LISTs
*/
@@ -74,19 +79,30 @@ struct _lol {
LIST *list[ LOL_MAX ];
};
+LIST * list_new( OBJECT * value );
LIST * list_append( LIST *l, LIST *nl );
-LIST * list_copy( LIST *l, LIST *nl );
+LIST * list_copy( LIST *l );
+LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last );
void list_free( LIST *head );
-LIST * list_new( LIST *head, char *string );
+LIST * list_push_back( LIST *head, OBJECT *string );
void list_print( LIST *l );
int list_length( LIST *l );
LIST * list_sublist( LIST *l, int start, int count );
LIST * list_pop_front( LIST *l );
LIST * list_sort( LIST *l);
LIST * list_unique( LIST *sorted_list);
-int list_in(LIST* l, char* value);
-
-# define list_next( l ) ((l)->next)
+int list_in(LIST* l, OBJECT* value);
+LIST * list_reverse( LIST * );
+int list_cmp( LIST * lhs, LIST * rhs );
+int list_is_sublist( LIST * sub, LIST * l );
+void list_done();
+
+LISTITER list_begin( LIST * );
+LISTITER list_end( LIST * );
+# define list_next( it ) ((it) + 1)
+# define list_item( it ) (*(it))
+# define list_empty( l ) ( (l) == L0 )
+# define list_front( l ) list_item( list_begin( l ) )
# define L0 ((LIST *)0)
@@ -95,7 +111,7 @@ void lol_init( LOL *lol );
void lol_free( LOL *lol );
LIST * lol_get( LOL *lol, int i );
void lol_print( LOL *lol );
-void lol_build( LOL* lol, char** elements );
+void lol_build( LOL* lol, const char** elements );
#ifdef HAVE_PYTHON
diff --git a/tools/build/v2/engine/make.c b/tools/build/v2/engine/make.c
index c871f0be2d..96416cbd52 100644
--- a/tools/build/v2/engine/make.c
+++ b/tools/build/v2/engine/make.c
@@ -58,7 +58,7 @@
#endif
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "headers.h"
#include "command.h"
@@ -106,9 +106,8 @@ static const char * target_bind[] =
* make() - make a target, given its name.
*/
-int make( int n_targets, char const * * targets, int anyhow )
+int make( LIST * targets, int anyhow )
{
- int i;
COUNTS counts[ 1 ];
int status = 0; /* 1 if anything fails */
@@ -124,16 +123,24 @@ int make( int n_targets, char const * * targets, int anyhow )
bind_explicitly_located_targets();
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE0 );
- for ( i = 0; i < n_targets; ++i )
- make0( bindtarget( targets[ i ] ), 0, 0, counts, anyhow );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ if ( t->fate == T_FATE_INIT )
+ make0( t, 0, 0, counts, anyhow );
+ }
PROFILE_EXIT( MAKE_MAKE0 );
}
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_GRAPH )
- for ( i = 0; i < n_targets; ++i )
- dependGraphOutput( bindtarget( targets[ i ] ), 0 );
+ {
+ LISTITER iter, end;
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ dependGraphOutput( bindtarget( list_item( iter ) ), 0 );
+ }
#endif
if ( DEBUG_MAKE )
@@ -155,16 +162,13 @@ int make( int n_targets, char const * * targets, int anyhow )
counts->cantmake > 1 ? "s" : "" );
}
-#ifdef OPT_HEADER_CACHE_EXT
- hcache_done();
-#endif
-
status = counts->cantfind || counts->cantmake;
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE1 );
- for ( i = 0; i < n_targets; ++i )
- status |= make1( bindtarget( targets[ i ] ) );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ status |= make1( bindtarget( list_item( iter ) ) );
PROFILE_EXIT( MAKE_MAKE1 );
}
@@ -195,7 +199,7 @@ static void update_dependants( TARGET * t )
if ( DEBUG_FATE )
{
printf( "fate change %s from %s to %s (as dependant of %s)\n",
- p->name, target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], t->name );
+ object_str( p->name ), target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], object_str( t->name ) );
}
/* If we are done visiting it, go back and make sure its dependants
@@ -224,7 +228,7 @@ static void force_rebuilds( TARGET * t )
{
if ( DEBUG_FATE )
printf( "fate change %s from %s to %s (by rebuild)\n",
- r->name, target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
+ object_str( r->name ), target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
/* Force rebuild it. */
r->fate = T_FATE_REBUILD;
@@ -266,14 +270,14 @@ void make0
#endif
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
/*
* Step 1: initialize
*/
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
t->fate = T_FATE_MAKING;
@@ -284,12 +288,13 @@ void make0
/* Step 2a: set "on target" variables. */
s = copysettings( t->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
/* Step 2b: find and timestamp the target file (if it is a file). */
if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
{
- char * another_target;
+ OBJECT * another_target;
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, &another_target,
t->flags & T_FLAG_ISFILE );
/* If it was detected that this target refers to an already existing and
@@ -317,10 +322,10 @@ void make0
#ifdef OPT_SEMAPHORE
{
- LIST * var = var_get( "JAM_SEMAPHORE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
+ if ( !list_empty( var ) )
{
- TARGET * semaphore = bindtarget( var->string );
+ TARGET * semaphore = bindtarget( list_front( var ) );
semaphore->progress = T_MAKE_SEMAPHORE;
t->semaphore = semaphore;
}
@@ -332,7 +337,7 @@ void make0
headers( t );
/* Step 2d: reset "on target" variables. */
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
/*
@@ -341,9 +346,9 @@ void make0
if ( DEBUG_BIND )
{
- if ( strcmp( t->name, t->boundname ) )
+ if ( ! object_equal( t->name, t->boundname ) )
printf( "bind\t--\t%s%s: %s\n",
- spaces( depth ), t->name, t->boundname );
+ spaces( depth ), object_str( t->name ), object_str( t->boundname ) );
switch ( t->binding )
{
@@ -351,12 +356,12 @@ void make0
case T_BIND_MISSING:
case T_BIND_PARENTS:
printf( "time\t--\t%s%s: %s\n",
- spaces( depth ), t->name, target_bind[ (int) t->binding ] );
+ spaces( depth ), object_str( t->name ), target_bind[ (int) t->binding ] );
break;
case T_BIND_EXISTS:
printf( "time\t--\t%s%s: %s",
- spaces( depth ), t->name, ctime( &t->time ) );
+ spaces( depth ), object_str( t->name ), ctime( &t->time ) );
break;
}
}
@@ -376,7 +381,7 @@ void make0
if ( c->target->fate == T_FATE_INIT )
make0( c->target, ptime, depth + 1, counts, anyhow );
else if ( c->target->fate == T_FATE_MAKING && !internal )
- printf( "warning: %s depends on itself\n", c->target->name );
+ printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
}
/* Step 3b: recursively make0() internal includes node. */
@@ -420,8 +425,8 @@ void make0
if ( DEBUG_FATE )
if ( fate < c->target->fate )
printf( "fate change %s from %s to %s by dependency %s\n",
- t->name, target_fate[(int) fate], target_fate[(int) c->target->fate],
- c->target->name );
+ object_str( t->name ), target_fate[(int) fate], target_fate[(int) c->target->fate],
+ object_str( c->target->name ) );
#endif
}
@@ -445,8 +450,8 @@ void make0
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_FATE )
if ( fate != T_FATE_STABLE )
- printf( "fate change %s back to stable, NOUPDATE.\n", t->name
- );
+ printf( "fate change %s back to stable, NOUPDATE.\n",
+ object_str( t->name ) );
#endif
last = 0;
@@ -541,10 +546,10 @@ void make0
if ( DEBUG_FATE && ( fate != savedFate ) )
{
if ( savedFate == T_FATE_STABLE )
- printf( "fate change %s set to %s%s\n", t->name,
+ printf( "fate change %s set to %s%s\n", object_str( t->name ),
target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
else
- printf( "fate change %s from %s to %s%s\n", t->name,
+ printf( "fate change %s from %s to %s%s\n", object_str( t->name ),
target_fate[ savedFate ], target_fate[ fate ],
oldTimeStamp ? " (by timestamp)" : "" );
}
@@ -564,13 +569,13 @@ void make0
if ( DEBUG_FATE )
printf( "fate change %s to STABLE from %s, "
"no actions, no dependencies and do not care\n",
- t->name, target_fate[ fate ] );
+ object_str( t->name ), target_fate[ fate ] );
#endif
fate = T_FATE_STABLE;
}
else
{
- printf( "don't know how to make %s\n", t->name );
+ printf( "don't know how to make %s\n", object_str( t->name ) );
fate = T_FATE_CANTFIND;
}
}
@@ -637,7 +642,7 @@ void make0
if ( DEBUG_MAKEPROG )
printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int) t->fate ],
- spaces( depth ), t->name );
+ spaces( depth ), object_str( t->name ) );
}
@@ -648,10 +653,10 @@ static const char * target_name( TARGET * t )
static char buf[ 1000 ];
if ( t->flags & T_FLAG_INTERNAL )
{
- sprintf( buf, "%s (internal node)", t->name );
+ sprintf( buf, "%s (internal node)", object_str( t->name ) );
return buf;
}
- return t->name;
+ return object_str( t->name );
}
@@ -681,8 +686,8 @@ static void dependGraphOutput( TARGET * t, int depth )
break;
}
- if ( strcmp( t->name, t->boundname ) )
- printf( " %s Loc: %s\n", spaces( depth ), t->boundname );
+ if ( ! object_equal( t->name, t->boundname ) )
+ printf( " %s Loc: %s\n", spaces( depth ), object_str( t->boundname ) );
switch ( t->fate )
{
@@ -792,12 +797,12 @@ static TARGETS * make0sort( TARGETS * chain )
}
-static LIST * targets_to_update_ = 0;
+static LIST * targets_to_update_ = L0;
-void mark_target_for_updating( char * target )
+void mark_target_for_updating( OBJECT * target )
{
- targets_to_update_ = list_new( targets_to_update_, target );
+ targets_to_update_ = list_push_back( targets_to_update_, object_copy( target ) );
}
@@ -810,5 +815,5 @@ LIST * targets_to_update()
void clear_targets_to_update()
{
list_free( targets_to_update_ );
- targets_to_update_ = 0;
+ targets_to_update_ = L0;
}
diff --git a/tools/build/v2/engine/make.h b/tools/build/v2/engine/make.h
index b372263e19..e0c7906583 100644
--- a/tools/build/v2/engine/make.h
+++ b/tools/build/v2/engine/make.h
@@ -8,10 +8,14 @@
* make.h - bring a target up to date, once rules are in place
*/
+#ifndef MAKE_SW20111118_H
+#define MAKE_SW20111118_H
+
#include "lists.h"
+#include "object.h"
-int make( int n_targets, const char **targets, int anyhow );
-int make1( TARGET *t );
+int make( LIST * targets, int anyhow );
+int make1( TARGET * t );
typedef struct {
int temp;
@@ -30,12 +34,14 @@ void make0( TARGET *t, TARGET *p, int depth,
/*
* Specifies that the target should be updated.
*/
-void mark_target_for_updating(char *target);
+void mark_target_for_updating( OBJECT * target );
/*
* Returns the list of all the target previously passed to 'mark_target_for_updating'.
*/
-LIST *targets_to_update();
+LIST * targets_to_update();
/*
* Cleasr/unmarks all targets that are currently marked for update.
*/
void clear_targets_to_update();
+
+#endif
diff --git a/tools/build/v2/engine/make1.c b/tools/build/v2/engine/make1.c
index 8001f33390..47132419a8 100644
--- a/tools/build/v2/engine/make1.c
+++ b/tools/build/v2/engine/make1.c
@@ -57,7 +57,7 @@
#include "headers.h"
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "command.h"
#include "execcmd.h"
@@ -72,7 +72,7 @@
static CMD * make1cmds ( TARGET * );
static LIST * make1list ( LIST *, TARGETS *, int flags );
-static SETTINGS * make1settings( LIST * vars );
+static SETTINGS * make1settings( struct module_t * module, LIST * vars );
static void make1bind ( TARGET * );
/* Ugly static - it is too hard to carry it through the callbacks. */
@@ -107,7 +107,7 @@ static void make1atail ( state * );
static void make1b ( state * );
static void make1c ( state * );
static void make1d ( state * );
-static void make_closure( void * closure, int status, timing_info *, char *, char * );
+static void make_closure( void * closure, int status, timing_info *, const char *, const char * );
typedef struct _stack
{
@@ -281,6 +281,15 @@ static void make1a( state * pState )
++pState->parent->asynccnt;
}
+ /*
+ * If the target has been previously updated with -n in
+ * effect, and we're ignoring -n, update it for real.
+ */
+ if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE )
+ {
+ pState->t->progress = T_MAKE_INIT;
+ }
+
/* If this target is already being processed then do nothing. There is no
* need to start processing the same target all over again.
*/
@@ -350,10 +359,10 @@ static void make1atail( state * pState )
static void make1b( state * pState )
{
- TARGET * t = pState->t;
- TARGETS * c;
- TARGET * failed = 0;
- char * failed_name = "dependencies";
+ TARGET * t = pState->t;
+ TARGETS * c;
+ TARGET * failed = 0;
+ const char * failed_name = "dependencies";
/* If any dependencies are still outstanding, wait until they call make1b()
* to signal their completion.
@@ -376,7 +385,7 @@ static void make1b( state * pState )
if ( DEBUG_EXECCMD )
printf( "SEM: %s is busy, delaying launch of %s\n",
- t->semaphore->name, t->name );
+ object_str( t->semaphore->name ), object_str( t->name ) );
pop_state( &state_stack );
return;
}
@@ -384,13 +393,21 @@ static void make1b( state * pState )
/* Now ready to build target 't', if dependencies built OK. */
- /* Collect status from dependencies. */
- for ( c = t->depends; c; c = c->next )
- if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
- {
- failed = c->target;
- pState->t->status = c->target->status;
- }
+ /* Collect status from dependencies. If -n was passed then
+ * act as though all dependencies built correctly. The only
+ * way they can fail is if UPDATE_NOW was called. If
+ * the dependencies can't be found or we got an interrupt,
+ * we can't get here.
+ */
+ if ( !globs.noexec )
+ {
+ for ( c = t->depends; c; c = c->next )
+ if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ {
+ failed = c->target;
+ pState->t->status = c->target->status;
+ }
+ }
/* If an internal header node failed to build, we want to output the target
* that it failed on.
*/
@@ -398,7 +415,7 @@ static void make1b( state * pState )
{
failed_name = failed->flags & T_FLAG_INTERNAL
? failed->failed
- : failed->name;
+ : object_str( failed->name );
}
t->failed = failed_name;
@@ -410,11 +427,11 @@ static void make1b( state * pState )
++counts->skipped;
if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
{
- if ( !unlink( pState->t->boundname ) )
- printf( "...removing outdated %s\n", pState->t->boundname );
+ if ( !unlink( object_str( pState->t->boundname ) ) )
+ printf( "...removing outdated %s\n", object_str( pState->t->boundname ) );
}
else
- printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
+ printf( "...skipped %s for lack of %s...\n", object_str( pState->t->name ), failed_name );
}
if ( pState->t->status == EXEC_CMD_OK )
@@ -436,7 +453,7 @@ static void make1b( state * pState )
case T_FATE_ISTMP:
if ( DEBUG_MAKE )
- printf( "...using %s...\n", pState->t->name );
+ printf( "...using %s...\n", object_str( pState->t->name ) );
break;
case T_FATE_TOUCHED:
@@ -467,7 +484,7 @@ static void make1b( state * pState )
/* All possible fates should have been accounted for by now. */
default:
- printf( "ERROR: %s has bad fate %d", pState->t->name,
+ printf( "ERROR: %s has bad fate %d", object_str( pState->t->name ),
pState->t->fate );
abort();
}
@@ -484,8 +501,8 @@ static void make1b( state * pState )
{
++pState->t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
- pState->t->name );
+ printf( "SEM: %s now used by %s\n", object_str( pState->t->semaphore->name ),
+ object_str( pState->t->name ) );
}
#endif
@@ -508,16 +525,16 @@ static void make1c( state * pState )
if ( cmd && ( pState->t->status == EXEC_CMD_OK ) )
{
- char * rule_name = 0;
- char * target = 0;
+ const char * rule_name = 0;
+ const char * target = 0;
if ( DEBUG_MAKEQ ||
( !( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE ) )
{
- rule_name = cmd->rule->name;
- target = lol_get( &cmd->args, 0 )->string;
+ rule_name = object_str( cmd->rule->name );
+ target = object_str( list_front( lol_get( &cmd->args, 0 ) ) );
if ( globs.noexec )
- out_action( rule_name, target, cmd->buf, "", "", EXIT_OK );
+ out_action( rule_name, target, cmd->buf->value, "", "", EXIT_OK );
}
if ( globs.noexec )
@@ -529,7 +546,7 @@ static void make1c( state * pState )
{
/* Pop state first because exec_cmd() could push state. */
pop_state( &state_stack );
- exec_cmd( cmd->buf, make_closure, pState->t, cmd->shell, rule_name,
+ exec_cmd( cmd->buf->value, make_closure, pState->t, cmd->shell, rule_name,
target );
}
}
@@ -560,13 +577,17 @@ static void make1c( state * pState )
TARGET * t = pState->t;
TARGET * additional_includes = NULL;
- t->progress = T_MAKE_DONE;
+ if ( globs.noexec )
+ t->progress = T_MAKE_NOEXEC_DONE;
+ else
+ t->progress = T_MAKE_DONE;
/* Target has been updated so rescan it for dependencies. */
if ( ( t->fate >= T_FATE_MISSING ) &&
( t->status == EXEC_CMD_OK ) &&
!t->rescanned )
{
+ TARGET * saved_includes;
TARGET * target_to_rescan = t;
SETTINGS * s;
@@ -576,16 +597,21 @@ static void make1c( state * pState )
target_to_rescan = t->original_target;
/* Clean current includes. */
+ saved_includes = target_to_rescan->includes;
target_to_rescan->includes = 0;
s = copysettings( target_to_rescan->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
headers( target_to_rescan );
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
if ( target_to_rescan->includes )
{
+ /* Link the old includes on to make sure that it gets
+ * cleaned up correctly.
+ */
+ target_to_rescan->includes->includes = saved_includes;
target_to_rescan->includes->rescanned = 1;
/* Tricky. The parents have already been processed, but they
* have not seen the internal node, because it was just
@@ -604,6 +630,10 @@ static void make1c( state * pState )
/* Will be processed below. */
additional_includes = target_to_rescan->includes;
}
+ else
+ {
+ target_to_rescan->includes = saved_includes;
+ }
}
if ( additional_includes )
@@ -621,7 +651,7 @@ static void make1c( state * pState )
--t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s is now free\n", t->semaphore->name );
+ printf( "SEM: %s is now free\n", object_str( t->semaphore->name ) );
/* If anything is waiting, notify the next target. There is no
* point in notifying waiting targets, since they will be
@@ -635,7 +665,7 @@ static void make1c( state * pState )
t->semaphore->parents = first->next;
if ( DEBUG_EXECCMD )
- printf( "SEM: placing %s on stack\n", first->target->name );
+ printf( "SEM: placing %s on stack\n", object_str( first->target->name ) );
push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B );
BJAM_FREE( first );
}
@@ -662,11 +692,11 @@ static void call_timing_rule( TARGET * target, timing_info * time )
{
LIST * timing_rule;
- pushsettings( target->settings );
- timing_rule = var_get( "__TIMING_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ timing_rule = var_get( root_module(), constant_TIMING_RULE );
+ popsettings( root_module(), target->settings );
- if ( timing_rule )
+ if ( !list_empty( timing_rule ) )
{
/* rule timing-rule ( args * : target : start end user system ) */
@@ -675,20 +705,20 @@ static void call_timing_rule( TARGET * target, timing_info * time )
frame_init( frame );
/* args * :: $(__TIMING_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, timing_rule->next ) );
+ lol_add( frame->args, list_copy_range( timing_rule, list_next( list_begin( timing_rule ) ), list_end( timing_rule ) ) );
/* target :: the name of the target */
- lol_add( frame->args, list_new( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* start end user system :: info about the action command */
- lol_add( frame->args, list_new( list_new( list_new( list_new( L0,
+ lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new(
outf_time ( time->start ) ),
outf_time ( time->end ) ),
outf_double( time->user ) ),
outf_double( time->system ) ) );
/* Call the rule. */
- evaluate_rule( timing_rule->string, frame );
+ evaluate_rule( list_front( timing_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -707,17 +737,17 @@ static void call_action_rule
TARGET * target,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
- LIST * action_rule;
+ LIST * action_rule;
- pushsettings( target->settings );
- action_rule = var_get( "__ACTION_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ action_rule = var_get( root_module(), constant_ACTION_RULE );
+ popsettings( root_module(), target->settings );
- if ( action_rule )
+ if ( !list_empty( action_rule ) )
{
/* rule action-rule (
args * :
@@ -730,15 +760,15 @@ static void call_action_rule
frame_init( frame );
/* args * :: $(__ACTION_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, action_rule->next ) );
+ lol_add( frame->args, list_copy_range( action_rule, list_next( list_begin( action_rule ) ), list_end( action_rule ) ) );
/* target :: the name of the target */
- lol_add( frame->args, list_new( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* command status start end user system :: info about the action command */
lol_add( frame->args,
- list_new( list_new( list_new( list_new( list_new( list_new( L0,
- newstr( executed_command ) ),
+ list_push_back( list_push_back( list_push_back( list_push_back( list_push_back( list_new(
+ object_new( executed_command ) ),
outf_int( status ) ),
outf_time( time->start ) ),
outf_time( time->end ) ),
@@ -747,12 +777,12 @@ static void call_action_rule
/* output ? :: the output of the action command */
if ( command_output )
- lol_add( frame->args, list_new( L0, newstr( command_output ) ) );
+ lol_add( frame->args, list_new( object_new( command_output ) ) );
else
lol_add( frame->args, L0 );
/* Call the rule. */
- evaluate_rule( action_rule->string, frame );
+ evaluate_rule( list_front( action_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -770,8 +800,8 @@ static void make_closure
void * closure,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
TARGET * built = (TARGET *)closure;
@@ -801,7 +831,7 @@ static void make1d( state * pState )
CMD * cmd = (CMD *)t->cmds;
int status = pState->status;
- if ( t->flags & T_FLAG_FAIL_EXPECTED )
+ if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec )
{
/* Invert execution result when FAIL_EXPECTED has been applied. */
switch ( status )
@@ -823,9 +853,9 @@ static void make1d( state * pState )
if ( ( status == EXEC_CMD_FAIL ) && DEBUG_MAKE )
{
if ( !DEBUG_EXEC )
- printf( "%s\n", cmd->buf );
+ printf( "%s\n", cmd->buf->value );
- printf( "...failed %s ", cmd->rule->name );
+ printf( "...failed %s ", object_str( cmd->rule->name ) );
list_print( lol_get( &cmd->args, 0 ) );
printf( "...\n" );
}
@@ -842,16 +872,17 @@ static void make1d( state * pState )
if (status != EXEC_CMD_OK)
{
LIST * targets = lol_get( &cmd->args, 0 );
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
int need_unlink = 1;
- TARGET* t = bindtarget ( targets->string );
+ TARGET* t = bindtarget ( list_item( iter ) );
if (t->flags & T_FLAG_PRECIOUS)
{
need_unlink = 0;
}
- if (need_unlink && !unlink( targets->string ) )
- printf( "...removing %s\n", targets->string );
+ if (need_unlink && !unlink( object_str( list_item( iter ) ) ) )
+ printf( "...removing %s\n", object_str( list_item( iter ) ) );
}
}
@@ -878,29 +909,17 @@ static void swap_settings
TARGET * new_target
)
{
- if ( new_module == root_module() )
- new_module = 0;
-
if ( ( new_target == *current_target ) && ( new_module == *current_module ) )
return;
if ( *current_target )
- popsettings( (*current_target)->settings );
-
- if ( new_module != *current_module )
- {
- if ( *current_module )
- exit_module( *current_module );
+ popsettings( *current_module, (*current_target)->settings );
- *current_module = new_module;
-
- if ( new_module )
- enter_module( new_module );
- }
+ if ( new_target )
+ pushsettings( new_module, new_target->settings );
+ *current_module = new_module;
*current_target = new_target;
- if ( new_target )
- pushsettings( new_target->settings );
}
@@ -916,10 +935,11 @@ static void swap_settings
static CMD * make1cmds( TARGET * t )
{
CMD * cmds = 0;
- LIST * shell = 0;
+ LIST * shell = L0;
module_t * settings_module = 0;
TARGET * settings_target = 0;
ACTIONS * a0;
+ int running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
/* Step through actions. Actions may be shared with other targets or grouped
* using RULE_TOGETHER, so actions already seen are skipped.
@@ -939,10 +959,10 @@ static CMD * make1cmds( TARGET * t )
/* Only do rules with commands to execute. If this action has already
* been executed, use saved status.
*/
- if ( !actions || a0->action->running )
+ if ( !actions || a0->action->running >= running_flag )
continue;
- a0->action->running = 1;
+ a0->action->running = running_flag;
/* Make LISTS of targets and sources. If `execute together` has been
* specified for this rule, tack on sources from each instance of this
@@ -952,28 +972,30 @@ static CMD * make1cmds( TARGET * t )
ns = make1list( L0, a0->action->sources, actions->flags );
if ( actions->flags & RULE_TOGETHER )
for ( a1 = a0->next; a1; a1 = a1->next )
- if ( a1->action->rule == rule && !a1->action->running )
+ if ( a1->action->rule == rule && a1->action->running < running_flag )
{
ns = make1list( ns, a1->action->sources, actions->flags );
- a1->action->running = 1;
+ a1->action->running = running_flag;
}
/* If doing only updated (or existing) sources, but none have been
* updated (or exist), skip this action.
*/
- if ( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ if ( list_empty( ns ) && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
{
list_free( nt );
continue;
}
swap_settings( &settings_module, &settings_target, rule->module, t );
- if ( !shell )
- shell = var_get( "JAMSHELL" ); /* shell is per-target */
+ if ( list_empty( shell ) )
+ {
+ shell = var_get( rule->module, constant_JAMSHELL ); /* shell is per-target */
+ }
/* If we had 'actions xxx bind vars' we bind the vars now. */
- boundvars = make1settings( actions->bindlist );
- pushsettings( boundvars );
+ boundvars = make1settings( rule->module, actions->bindlist );
+ pushsettings( rule->module, boundvars );
/*
* Build command, starting with all source args.
@@ -998,9 +1020,9 @@ static CMD * make1cmds( TARGET * t )
{
/* Build cmd: cmd_new consumes its lists. */
CMD * cmd = cmd_new( rule,
- list_copy( L0, nt ),
+ list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_copy( L0, shell ) );
+ list_copy( shell ) );
if ( cmd )
{
@@ -1018,14 +1040,14 @@ static CMD * make1cmds( TARGET * t )
else
{
/* Too long and not splittable. */
- printf( "%s actions too long (max %d):\n", rule->name, MAXLINE
+ printf( "%s actions too long (max %d):\n", object_str( rule->name ), MAXLINE
);
/* Tell the user what didn't fit. */
- cmd = cmd_new( rule, list_copy( L0, nt ),
+ cmd = cmd_new( rule, list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_new( L0, newstr( "%" ) ) );
- fputs( cmd->buf, stdout );
+ list_new( object_copy( constant_percent ) ) );
+ fputs( cmd->buf->value, stdout );
exit( EXITBAD );
}
}
@@ -1038,7 +1060,7 @@ static CMD * make1cmds( TARGET * t )
/* Free the variables whose values were bound by 'actions xxx bind
* vars'.
*/
- popsettings( boundvars );
+ popsettings( rule->module, boundvars );
freesettings( boundvars );
}
@@ -1077,16 +1099,16 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
/* Prohibit duplicates for RULE_TOGETHER. */
if ( flags & RULE_TOGETHER )
{
- LIST * m;
- for ( m = l; m; m = m->next )
- if ( !strcmp( m->string, t->boundname ) )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), t->boundname ) )
break;
- if ( m )
+ if ( iter != end )
continue;
}
/* Build new list. */
- l = list_new( l, copystr( t->boundname ) );
+ l = list_push_back( l, object_copy( t->boundname ) );
}
return l;
@@ -1097,29 +1119,31 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
* make1settings() - for vars that get bound values, build up replacement lists.
*/
-static SETTINGS * make1settings( LIST * vars )
+static SETTINGS * make1settings( struct module_t * module, LIST * vars )
{
SETTINGS * settings = 0;
- for ( ; vars; vars = list_next( vars ) )
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
{
- LIST * l = var_get( vars->string );
- LIST * nl = 0;
+ LIST * l = var_get( module, list_item( vars_iter ) );
+ LIST * nl = L0;
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Make sure the target is bound. */
if ( t->binding == T_BIND_UNBOUND )
make1bind( t );
/* Build a new list. */
- nl = list_new( nl, copystr( t->boundname ) );
+ nl = list_push_back( nl, object_copy( t->boundname ) );
}
/* Add to settings chain. */
- settings = addsettings( settings, VAR_SET, vars->string, nl );
+ settings = addsettings( settings, VAR_SET, list_item( vars_iter ), nl );
}
return settings;
@@ -1138,8 +1162,9 @@ static void make1bind( TARGET * t )
if ( t->flags & T_FLAG_NOTFILE )
return;
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, ( t->flags & T_FLAG_ISFILE ) );
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
}
diff --git a/tools/build/v2/engine/modules.c b/tools/build/v2/engine/modules.c
index 7295259415..8898d18bb0 100644
--- a/tools/build/v2/engine/modules.c
+++ b/tools/build/v2/engine/modules.c
@@ -8,64 +8,54 @@
#include "modules.h"
#include "string.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
#include "parse.h"
#include "rules.h"
#include "variable.h"
#include "strings.h"
+#include "native.h"
#include <assert.h>
static struct hash * module_hash = 0;
+static module_t root;
-
-static char * new_module_str( module_t * m, char * suffix )
-{
- char * result;
- string s;
- string_copy( &s, m->name );
- string_append( &s, suffix );
- result = newstr( s.value );
- string_free( &s );
- return result;
-}
-
-
-module_t * bindmodule( char * name )
+module_t * bindmodule( OBJECT * name )
{
- PROFILE_ENTER( BINDMODULE );
-
- string s;
- module_t m_;
- module_t * m = &m_;
-
- if ( !module_hash )
- module_hash = hashinit( sizeof( module_t ), "modules" );
- string_new( &s );
- if ( name )
+ if ( !name )
{
- string_append( &s, name );
- string_push_back( &s, '.' );
+ return &root;
}
-
- m->name = s.value;
-
- if ( hashenter( module_hash, (HASHDATA * *)&m ) )
+ else
{
- m->name = newstr( m->name );
- m->variables = 0;
- m->rules = 0;
- m->imported_modules = 0;
- m->class_module = 0;
- m->native_rules = 0;
- m->user_module = 0;
+ PROFILE_ENTER( BINDMODULE );
+
+ module_t * m;
+ int found;
+
+ if ( !module_hash )
+ module_hash = hashinit( sizeof( module_t ), "modules" );
+
+ m = (module_t *)hash_insert( module_hash, name, &found );
+ if ( !found )
+ {
+ m->name = object_copy( name );
+ m->variables = 0;
+ m->variable_indices = 0;
+ m->num_fixed_variables = 0;
+ m->fixed_variables = 0;
+ m->rules = 0;
+ m->imported_modules = 0;
+ m->class_module = 0;
+ m->native_rules = 0;
+ m->user_module = 0;
+ }
+
+ PROFILE_EXIT( BINDMODULE );
+
+ return m;
}
- string_free( &s );
-
- PROFILE_EXIT( BINDMODULE );
-
- return m;
}
/*
@@ -74,7 +64,7 @@ module_t * bindmodule( char * name )
struct hash * demand_rules( module_t * m )
{
if ( !m->rules )
- m->rules = hashinit( sizeof( RULE ), new_module_str( m, "rules" ) );
+ m->rules = hashinit( sizeof( RULE ), "rules" );
return m->rules;
}
@@ -89,43 +79,194 @@ static void delete_rule_( void * xrule, void * data )
}
+static void delete_native_rule( void * xrule, void * data )
+{
+ native_rule_t * rule = (native_rule_t *)xrule;
+ object_free( rule->name );
+ if ( rule->procedure )
+ function_free( rule->procedure );
+}
+
+
+static void delete_imported_modules( void * xmodule_name, void * data )
+{
+ object_free( *(OBJECT * *)xmodule_name );
+}
+
+static void free_fixed_variable( void * xvar, void * data );
+
void delete_module( module_t * m )
{
/* Clear out all the rules. */
if ( m->rules )
{
hashenumerate( m->rules, delete_rule_, (void *)0 );
- hashdone( m->rules );
+ hash_free( m->rules );
m->rules = 0;
}
+ if ( m->native_rules )
+ {
+ hashenumerate( m->native_rules, delete_native_rule, (void *)0 );
+ hash_free( m->native_rules );
+ m->native_rules = 0;
+ }
+
if ( m->variables )
{
- var_hash_swap( &m->variables );
- var_done();
- var_hash_swap( &m->variables );
+ var_done( m );
m->variables = 0;
}
+
+ if ( m->fixed_variables )
+ {
+ int i;
+ for ( i = 0; i < m->num_fixed_variables; ++i )
+ {
+ list_free( m->fixed_variables[ i ] );
+ }
+ BJAM_FREE( m->fixed_variables );
+ m->fixed_variables = 0;
+ }
+
+ if ( m->variable_indices )
+ {
+ hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 );
+ hash_free( m->variable_indices );
+ m->variable_indices = 0;
+ }
+
+ if ( m->imported_modules )
+ {
+ hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
+ hash_free( m->imported_modules );
+ m->imported_modules = 0;
+ }
}
-module_t * root_module()
+struct module_stats
+{
+ OBJECT * module_name;
+ struct hashstats rules_stats[ 1 ];
+ struct hashstats variables_stats[ 1 ];
+ struct hashstats variable_indices_stats[ 1 ];
+ struct hashstats imported_modules_stats[ 1 ];
+};
+
+
+static void module_stat( struct hash * hp, OBJECT * module, const char * name )
+{
+ if ( hp )
+ {
+ struct hashstats stats[ 1 ];
+ string id[ 1 ];
+ hashstats_init( stats );
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_push_back( id, ' ' );
+ string_append( id, name );
+
+ hashstats_add( stats, hp );
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name )
+{
+ if ( stats->item_size )
+ {
+ string id[ 1 ];
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_append( id, " object " );
+ string_append( id, name );
+
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void stat_module( void * xmodule, void * data )
+{
+ module_t *m = (module_t *)xmodule;
+
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_info = (struct hash *)data;
+ if ( m->class_module )
+ {
+ int found;
+ struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found );
+ if ( !found )
+ {
+ ms->module_name = m->class_module->name;
+ hashstats_init( ms->rules_stats );
+ hashstats_init( ms->variables_stats );
+ hashstats_init( ms->variable_indices_stats );
+ hashstats_init( ms->imported_modules_stats );
+ }
+
+ hashstats_add( ms->rules_stats, m->rules );
+ hashstats_add( ms->variables_stats, m->variables );
+ hashstats_add( ms->variable_indices_stats, m->variable_indices );
+ hashstats_add( ms->imported_modules_stats, m->imported_modules );
+ }
+ else
+ {
+ module_stat( m->rules, m->name, "rules" );
+ module_stat( m->variables, m->name, "variables" );
+ module_stat( m->variable_indices, m->name, "fixed variables" );
+ module_stat( m->imported_modules, m->name, "imported modules" );
+ }
+ }
+
+ delete_module( m );
+ object_free( m->name );
+}
+
+static void print_class_stats( void * xstats, void * data )
{
- static module_t * root = 0;
- if ( !root )
- root = bindmodule( 0 );
- return root;
+ struct module_stats * stats = (struct module_stats *)xstats;
+ class_module_stat( stats->rules_stats, stats->module_name, "rules" );
+ class_module_stat( stats->variables_stats, stats->module_name, "variables" );
+ class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" );
+ class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" );
}
-void enter_module( module_t * m )
+
+static void delete_module_( void * xmodule, void * data )
{
- var_hash_swap( &m->variables );
+ module_t *m = (module_t *)xmodule;
+
+ delete_module( m );
+ object_free( m->name );
}
-void exit_module( module_t * m )
+void modules_done()
+{
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" );
+ hashenumerate( module_hash, stat_module, (void *)class_hash );
+ hashenumerate( class_hash, print_class_stats, (void *)0 );
+ hash_free( class_hash );
+ }
+ hashenumerate( module_hash, delete_module_, (void *)0 );
+ hashdone( module_hash );
+ module_hash = 0;
+ delete_module( &root );
+}
+
+module_t * root_module()
{
- var_hash_swap( &m->variables );
+ return &root;
}
@@ -134,16 +275,22 @@ void import_module( LIST * module_names, module_t * target_module )
PROFILE_ENTER( IMPORT_MODULE );
struct hash * h;
+ LISTITER iter, end;
if ( !target_module->imported_modules )
target_module->imported_modules = hashinit( sizeof( char * ), "imported" );
h = target_module->imported_modules;
- for ( ; module_names; module_names = module_names->next )
+ iter = list_begin( module_names ), end = list_end( module_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * s = module_names->string;
- char * * ss = &s;
- hashenter( h, (HASHDATA * *)&ss );
+ int found;
+ OBJECT * s = list_item( iter );
+ OBJECT * * ss = (OBJECT * *)hash_insert( h, s, &found );
+ if( !found )
+ {
+ *ss = object_copy( s );
+ }
}
PROFILE_EXIT( IMPORT_MODULE );
@@ -152,10 +299,10 @@ void import_module( LIST * module_names, module_t * target_module )
static void add_module_name( void * r_, void * result_ )
{
- char * * r = (char * *)r_;
+ OBJECT * * r = (OBJECT * *)r_;
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *r ) );
+ *result = list_push_back( *result, object_copy( *r ) );
}
@@ -166,3 +313,124 @@ LIST * imported_modules( module_t * module )
hashenumerate( module->imported_modules, add_module_name, &result );
return result;
}
+
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+struct fixed_variable
+{
+ OBJECT * key;
+ int n;
+};
+
+struct bind_vars_t
+{
+ module_t * module;
+ int counter;
+};
+
+static void free_fixed_variable( void * xvar, void * data )
+{
+ object_free( ( (struct fixed_variable *)xvar )->key );
+}
+
+static void bind_variables_for_rule( void * xrule, void * xdata )
+{
+ RULE * rule = (RULE *)xrule;
+ struct bind_vars_t * data = (struct bind_vars_t *)xdata;
+ if ( rule->procedure && rule->module == data->module )
+ rule->procedure = function_bind_variables( rule->procedure, data->module, &data->counter );
+}
+
+void module_bind_variables( struct module_t * m )
+{
+ if ( m != root_module() && m->rules )
+ {
+ struct bind_vars_t data;
+ data.module = m;
+ data.counter = m->num_fixed_variables;
+ hashenumerate( m->rules, &bind_variables_for_rule, &data );
+ module_set_fixed_variables( m, data.counter );
+ }
+}
+
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
+{
+ struct fixed_variable * v;
+ int found;
+
+ assert( !m->class_module );
+
+ if ( !m->variable_indices )
+ m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
+
+ v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
+ if ( !found )
+ {
+ v->key = object_copy( name );
+ v->n = (*counter)++;
+ }
+
+ return v->n;
+}
+
+LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
+
+static void load_fixed_variable( void * xvar, void * data )
+{
+ struct fixed_variable * var = (struct fixed_variable *)xvar;
+ struct module_t * m = (struct module_t *)data;
+ if ( var->n >= m->num_fixed_variables )
+ {
+ m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
+ }
+}
+
+void module_set_fixed_variables( struct module_t * m, int n_variables )
+{
+ /* Reallocate */
+ struct hash * variable_indices;
+ LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) );
+ if ( m->fixed_variables )
+ {
+ memcpy( fixed_variables, m->fixed_variables, n_variables * sizeof( LIST * ) );
+ BJAM_FREE( m->fixed_variables );
+ }
+ m->fixed_variables = fixed_variables;
+ if ( m->class_module )
+ {
+ variable_indices = m->class_module->variable_indices;
+ }
+ else
+ {
+ variable_indices = m->variable_indices;
+ }
+ if ( variable_indices )
+ hashenumerate( variable_indices, &load_fixed_variable, m );
+ m->num_fixed_variables = n_variables;
+}
+
+int module_get_fixed_var( struct module_t * m_, OBJECT * name )
+{
+ struct fixed_variable * v;
+ struct module_t * m = m_;
+
+ if ( m->class_module )
+ {
+ m = m->class_module;
+ }
+
+ if ( !m->variable_indices )
+ return -1;
+
+ v = (struct fixed_variable *)hash_find( m->variable_indices, name );
+ if ( v && v->n < m_->num_fixed_variables )
+ {
+ return v->n;
+ }
+ else
+ {
+ return -1;
+ }
+}
diff --git a/tools/build/v2/engine/modules.h b/tools/build/v2/engine/modules.h
index 60053a239f..a7d9752b8c 100644
--- a/tools/build/v2/engine/modules.h
+++ b/tools/build/v2/engine/modules.h
@@ -10,28 +10,44 @@
struct module_t
{
- char* name;
- struct hash* rules;
- struct hash* variables;
- struct hash* imported_modules;
- struct module_t* class_module;
- struct hash* native_rules;
+ OBJECT * name;
+ struct hash * rules;
+ struct hash * variables;
+ struct hash * variable_indices;
+ int num_fixed_variables;
+ LIST * * fixed_variables;
+ struct hash * imported_modules;
+ struct module_t * class_module;
+ struct hash * native_rules;
int user_module;
};
typedef struct module_t module_t ; /* MSVC debugger gets confused unless this is provided */
-module_t* bindmodule( char* name );
-module_t* root_module();
-void enter_module( module_t* );
-void exit_module( module_t* );
-void delete_module( module_t* );
+module_t * bindmodule( OBJECT * name );
+module_t * root_module();
+void delete_module( module_t * );
-void import_module(LIST* module_names, module_t* target_module);
+void import_module( LIST * module_names, module_t * target_module );
LIST* imported_modules(module_t* module);
-struct hash* demand_rules( module_t* );
+struct hash * demand_rules( module_t * );
+void module_bind_variables( struct module_t * m );
+
+/*
+ * After calling module_add_fixed_var, module_set_fixed_variables
+ * must be called before accessing any variables in the module.
+ */
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * n );
+void module_set_fixed_variables( struct module_t * m, int n );
+
+/*
+ * Returns the index of the variable or -1 if none exists.
+ */
+int module_get_fixed_var( struct module_t * m, OBJECT * name );
+
+void modules_done();
#endif
diff --git a/tools/build/v2/engine/modules/order.c b/tools/build/v2/engine/modules/order.c
index d77943a79c..ed632be3ac 100644
--- a/tools/build/v2/engine/modules/order.c
+++ b/tools/build/v2/engine/modules/order.c
@@ -5,18 +5,19 @@
#include "../native.h"
#include "../lists.h"
#include "../strings.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../variable.h"
/* Use quite klugy approach: when we add order dependency from 'a' to 'b',
just append 'b' to of value of variable 'a'.
*/
-LIST *add_pair( PARSE *parse, FRAME *frame )
+LIST *add_pair( FRAME *frame, int flags )
{
LIST* arg = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg ), end = list_end( arg );
- var_set(arg->string, list_copy(0, arg->next), VAR_APPEND);
+ var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next( iter ), end ), VAR_APPEND );
return L0;
}
@@ -24,11 +25,12 @@ LIST *add_pair( PARSE *parse, FRAME *frame )
/** Given a list and a value, returns position of that value in
the list, or -1 if not found.
*/
-int list_index(LIST* list, const char* value)
+int list_index(LIST* list, OBJECT* value)
{
int result = 0;
- for(; list; list = list->next, ++result) {
- if (strcmp(list->string, value) == 0)
+ LISTITER iter = list_begin(list), end = list_end(list);
+ for(; iter != end; iter = list_next(iter), ++result) {
+ if (object_equal(list_item(iter), value))
return result;
}
return -1;
@@ -74,12 +76,12 @@ void topological_sort(int** graph, int num_vertices, int* result)
BJAM_FREE(colors);
}
-LIST *order( PARSE *parse, FRAME *frame )
+LIST *order( FRAME *frame, int flags )
{
- LIST* arg = lol_get( frame->args, 0 );
- LIST* tmp;
- LIST* result = 0;
+ LIST* arg = lol_get( frame->args, 0 );
+ LIST* result = L0;
int src;
+ LISTITER iter = list_begin(arg), end = list_end(arg);
/* We need to create a graph of order dependencies between
the passed objects. We assume that there are no duplicates
@@ -89,15 +91,16 @@ LIST *order( PARSE *parse, FRAME *frame )
int** graph = (int**)BJAM_CALLOC(length, sizeof(int*));
int* order = (int*)BJAM_MALLOC((length+1)*sizeof(int));
- for(tmp = arg, src = 0; tmp; tmp = tmp->next, ++src) {
+ for(src = 0; iter != end; iter = list_next(iter), ++src) {
/* For all object this one depend upon, add elements
to 'graph' */
- LIST* dependencies = var_get(tmp->string);
+ LIST* dependencies = var_get(frame->module, list_item(iter));
int index = 0;
+ LISTITER dep_iter = list_begin(dependencies), dep_end = list_end(dependencies);
graph[src] = (int*)BJAM_CALLOC(list_length(dependencies)+1, sizeof(int));
- for(; dependencies; dependencies = dependencies->next) {
- int dst = list_index(arg, dependencies->string);
+ for(; dep_iter != dep_end; dep_iter = list_next(dep_iter)) {
+ int dst = list_index(arg, list_item(dep_iter));
if (dst != -1)
graph[src][index++] = dst;
}
@@ -110,9 +113,9 @@ LIST *order( PARSE *parse, FRAME *frame )
int index = length-1;
for(; index >= 0; --index) {
int i;
- tmp = arg;
- for (i = 0; i < order[index]; ++i, tmp = tmp->next);
- result = list_new(result, tmp->string);
+ iter = list_begin(arg), end = list_end(arg);
+ for (i = 0; i < order[index]; ++i, iter = list_next(iter));
+ result = list_push_back(result, object_copy(list_item(iter)));
}
}
@@ -131,12 +134,12 @@ LIST *order( PARSE *parse, FRAME *frame )
void init_order()
{
{
- char* args[] = { "first", "second", 0 };
+ const char* args[] = { "first", "second", 0 };
declare_native_rule("class@order", "add-pair", args, add_pair, 1);
}
{
- char* args[] = { "objects", "*", 0 };
+ const char* args[] = { "objects", "*", 0 };
declare_native_rule("class@order", "order", args, order, 1);
}
diff --git a/tools/build/v2/engine/modules/path.c b/tools/build/v2/engine/modules/path.c
index f5d0962246..ca243f03d6 100644
--- a/tools/build/v2/engine/modules/path.c
+++ b/tools/build/v2/engine/modules/path.c
@@ -4,17 +4,17 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
-LIST *path_exists( PARSE *parse, FRAME *frame )
+LIST *path_exists( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
time_t time;
- timestamp(l->string, &time);
+ timestamp(list_front(l), &time);
if (time != 0)
{
- return list_new(0, newstr("true"));
+ return list_new(object_new("true"));
}
else
{
@@ -25,7 +25,7 @@ LIST *path_exists( PARSE *parse, FRAME *frame )
void init_path()
{
{
- char* args[] = { "location", 0 };
+ const char* args[] = { "location", 0 };
declare_native_rule("path", "exists", args, path_exists, 1);
}
diff --git a/tools/build/v2/engine/modules/property-set.c b/tools/build/v2/engine/modules/property-set.c
index 2b0fb5d97b..9d0c5cf633 100644
--- a/tools/build/v2/engine/modules/property-set.c
+++ b/tools/build/v2/engine/modules/property-set.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../lists.h"
#include "../variable.h"
@@ -19,7 +19,7 @@ LIST* get_grist(char* f)
string_new(s);
string_append_range(s, f, end+1);
- result = list_new(0, newstr(s->value));
+ result = list_new(object_new(s->value));
string_free(s);
return result;
@@ -41,17 +41,18 @@ rule create ( raw-properties * )
}
*/
-LIST *property_set_create( PARSE *parse, FRAME *frame )
+LIST *property_set_create( FRAME *frame, int flags )
{
LIST* properties = lol_get( frame->args, 0 );
- LIST* sorted = 0;
+ LIST* sorted = L0;
#if 0
LIST* order_sensitive = 0;
#endif
LIST* unique;
- LIST* tmp;
LIST* val;
string var[1];
+ OBJECT* name;
+ LISTITER iter, end;
#if 0
/* Sort all properties which are not order sensitive */
@@ -59,9 +60,9 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
LIST* g = get_grist(tmp->string);
LIST* att = call_rule("feature.attributes", frame, g, 0);
if (list_in(att, "order-sensitive")) {
- order_sensitive = list_new( order_sensitive, tmp->string);
+ order_sensitive = list_new( order_sensitive, copystr(tmp->string));
} else {
- sorted = list_new( sorted, tmp->string);
+ sorted = list_new( sorted, copystr(tmp->string));
}
list_free(att);
}
@@ -76,22 +77,28 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
string_new(var);
string_append(var, ".ps.");
- for(tmp = unique; tmp; tmp = tmp->next) {
- string_append(var, tmp->string);
+ iter = list_begin( unique ), end = list_end( unique );
+ for( ; iter != end; iter = list_next( iter ) ) {
+ string_append(var, object_str( list_item( iter ) ));
string_push_back(var, '-');
}
- val = var_get(var->value);
- if (val == 0)
+ name = object_new(var->value);
+ val = var_get(frame->module, name);
+ if (list_empty(val))
{
- val = call_rule("new", frame,
- list_append(list_new(0, "property-set"), unique), 0);
+ OBJECT* rulename = object_new("new");
+ val = call_rule(rulename, frame,
+ list_append(list_new(object_new("property-set")), unique), 0);
+ object_free(rulename);
- var_set(newstr(var->value), list_copy(0, val), VAR_SET);
+ var_set(frame->module, name, list_copy(val), VAR_SET);
}
else
{
- val = list_copy(0, val);
+ list_free(unique);
+ val = list_copy(val);
}
+ object_free(name);
string_free(var);
/* The 'unique' variable is freed in 'call_rule'. */
@@ -104,7 +111,7 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
void init_property_set()
{
{
- char* args[] = { "raw-properties", "*", 0 };
+ const char* args[] = { "raw-properties", "*", 0 };
declare_native_rule("property-set", "create", args, property_set_create, 1);
}
}
diff --git a/tools/build/v2/engine/modules/regex.c b/tools/build/v2/engine/modules/regex.c
index d048ba1de4..9002f4bad3 100644
--- a/tools/build/v2/engine/modules/regex.c
+++ b/tools/build/v2/engine/modules/regex.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../regexp.h"
#include "../compile.h"
@@ -25,7 +25,7 @@ rule transform ( list * : pattern : indices * )
return $(result) ;
}
*/
-LIST *regex_transform( PARSE *parse, FRAME *frame )
+LIST *regex_transform( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
LIST* pattern = lol_get( frame->args, 1 );
@@ -33,18 +33,19 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
int* indices = 0;
int size;
int* p;
- LIST* result = 0;
+ LIST* result = L0;
string buf[1];
string_new(buf);
- if (indices_list)
+ if (!list_empty(indices_list))
{
+ LISTITER iter = list_begin(indices_list), end = list_end(indices_list);
size = list_length(indices_list);
indices = (int*)BJAM_MALLOC(size*sizeof(int));
- for(p = indices; indices_list; indices_list = indices_list->next)
+ for(p = indices; iter != end; iter = list_next(iter))
{
- *p++ = atoi(indices_list->string);
+ *p++ = atoi(object_str(list_item(iter)));
}
}
else
@@ -56,11 +57,12 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
{
/* Result is cached and intentionally never freed */
- regexp *re = regex_compile( pattern->string );
+ regexp *re = regex_compile( list_front( pattern ) );
- for(; l; l = l->next)
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if( regexec( re, l->string ) )
+ if( regexec( re, object_str( list_item( iter ) ) ) )
{
int i = 0;
for(; i < size; ++i)
@@ -73,7 +75,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
if (re->startp[index] != re->endp[index])
{
string_append_range( buf, re->startp[index], re->endp[index] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -90,7 +92,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
void init_regex()
{
{
- char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
+ const char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
declare_native_rule("regex", "transform", args, regex_transform, 2);
}
}
diff --git a/tools/build/v2/engine/modules/sequence.c b/tools/build/v2/engine/modules/sequence.c
index bda80d94c4..2b539966de 100644
--- a/tools/build/v2/engine/modules/sequence.c
+++ b/tools/build/v2/engine/modules/sequence.c
@@ -3,30 +3,35 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
# ifndef max
# define max( a,b ) ((a)>(b)?(a):(b))
# endif
-LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
+LIST *sequence_select_highest_ranked( FRAME *frame, int flags )
{
/* Returns all of 'elements' for which corresponding element in parallel */
/* list 'rank' is equal to the maximum value in 'rank'. */
LIST* elements = lol_get( frame->args, 0 );
LIST* rank = lol_get( frame->args, 1 );
+ LISTITER iter, end, elements_iter, elements_end;
- LIST* result = 0;
+ LIST* result = L0;
LIST* tmp;
int highest_rank = -1;
- for (tmp = rank; tmp; tmp = tmp->next)
- highest_rank = max(highest_rank, atoi(tmp->string));
-
- for (; rank; rank = rank->next, elements = elements->next)
- if (atoi(rank->string) == highest_rank)
- result = list_new(result, elements->string);
+ iter = list_begin(rank), end = list_end(rank);
+ for (; iter != end; iter = list_next(iter))
+ highest_rank = max(highest_rank, atoi(object_str(list_item(iter))));
+
+ iter = list_begin(rank), end = list_end(rank);
+ elements_iter = list_begin(elements), elements_end = list_end(elements);
+ for (; iter != end; iter = list_next(iter), elements_iter = list_next(elements_iter))
+ if (atoi(object_str(list_item(iter))) == highest_rank)
+ result = list_push_back(result, object_copy(list_item(elements_iter)));
return result;
}
@@ -34,7 +39,7 @@ LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
void init_sequence()
{
{
- char* args[] = { "elements", "*", ":", "rank", "*", 0 };
+ const char* args[] = { "elements", "*", ":", "rank", "*", 0 };
declare_native_rule("sequence", "select-highest-ranked", args,
sequence_select_highest_ranked, 1);
}
diff --git a/tools/build/v2/engine/modules/set.c b/tools/build/v2/engine/modules/set.c
index f8219403c5..77a314d57d 100644
--- a/tools/build/v2/engine/modules/set.c
+++ b/tools/build/v2/engine/modules/set.c
@@ -3,6 +3,7 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
/*
local result = ;
@@ -16,17 +17,18 @@
}
return $(result) ;
*/
-LIST *set_difference( PARSE *parse, FRAME *frame )
+LIST *set_difference( FRAME *frame, int flags )
{
LIST* b = lol_get( frame->args, 0 );
LIST* a = lol_get( frame->args, 1 );
- LIST* result = 0;
- for(; b; b = b->next)
+ LIST* result = L0;
+ LISTITER iter = list_begin( b ), end = list_end( b );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if (!list_in(a, b->string))
- result = list_new(result, b->string);
+ if (!list_in(a, list_item(iter)))
+ result = list_push_back(result, object_copy(list_item(iter)));
}
return result;
}
@@ -34,7 +36,7 @@ LIST *set_difference( PARSE *parse, FRAME *frame )
void init_set()
{
{
- char* args[] = { "B", "*", ":", "A", "*", 0 };
+ const char* args[] = { "B", "*", ":", "A", "*", 0 };
declare_native_rule("set", "difference", args, set_difference, 1);
}
diff --git a/tools/build/v2/engine/native.c b/tools/build/v2/engine/native.c
index 4c2899595e..b1d4278313 100644
--- a/tools/build/v2/engine/native.c
+++ b/tools/build/v2/engine/native.c
@@ -4,33 +4,36 @@
#include "native.h"
#include "hash.h"
+#include "object.h"
+#include "assert.h"
-# define P0 (PARSE *)0
-# define C0 (char *)0
-
-
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version)
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version )
{
- module_t* m = bindmodule(module);
- if (m->native_rules == 0) {
+ OBJECT * module_obj = 0;
+ module_t * m;
+ if ( module )
+ {
+ module_obj = object_new( module );
+ }
+ m = bindmodule( module_obj );
+ if ( module_obj )
+ {
+ object_free( module_obj );
+ }
+ if (m->native_rules == 0)
+ {
m->native_rules = hashinit( sizeof( native_rule_t ), "native rules");
}
{
- native_rule_t n, *np = &n;
- n.name = rule;
- if (args)
- {
- n.arguments = args_new();
- lol_build( n.arguments->data, args );
- }
- else
- {
- n.arguments = 0;
- }
- n.procedure = parse_make( f, P0, P0, P0, C0, C0, 0 );
- n.version = version;
- hashenter(m->native_rules, (HASHDATA**)&np);
+ native_rule_t *np;
+ OBJECT * name = object_new( rule );
+ int found;
+ np = (native_rule_t *)hash_insert( m->native_rules, name, &found );
+ np->name = name;
+ assert( !found );
+ np->procedure = function_builtin( f, 0, args );
+ np->version = version;
}
}
diff --git a/tools/build/v2/engine/native.h b/tools/build/v2/engine/native.h
index 3fc710b9c6..cdd63c844b 100644
--- a/tools/build/v2/engine/native.h
+++ b/tools/build/v2/engine/native.h
@@ -5,13 +5,16 @@
#ifndef NATIVE_H_VP_2003_12_09
#define NATIVE_H_VP_2003_12_09
+#include "lists.h"
+#include "object.h"
+#include "frames.h"
+#include "function.h"
#include "rules.h"
struct native_rule_t
{
- char* name;
- argument_list* arguments;
- PARSE* procedure;
+ OBJECT * name;
+ FUNCTION * procedure;
/* Version of the interface that the native rule provides.
It's possible that we want to change the set parameter
for existing native rule. In that case, version number
@@ -26,8 +29,8 @@ struct native_rule_t
/* MSVC debugger gets confused unless this is provided */
typedef struct native_rule_t native_rule_t ;
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version);
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version );
diff --git a/tools/build/v2/engine/newstr.c b/tools/build/v2/engine/newstr.c
deleted file mode 100644
index 6a229eb216..0000000000
--- a/tools/build/v2/engine/newstr.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "newstr.h"
-# include "hash.h"
-# include "compile.h"
-# include <stddef.h>
-# include <stdlib.h>
-
-/*
- * newstr.c - string manipulation routines
- *
- * To minimize string copying, string creation, copying, and freeing
- * is done through newstr.
- *
- * External functions:
- *
- * newstr() - return a dynamically allocated copy of a string
- * copystr() - return a copy of a string previously returned by newstr()
- * freestr() - free a string returned by newstr() or copystr()
- * str_done() - free string tables
- *
- * Once a string is passed to newstr(), the returned string is readonly.
- *
- * This implementation builds a hash table of all strings, so that multiple
- * calls of newstr() on the same string allocate memory for the string once.
- * Strings are never actually freed.
- */
-
-typedef char * STRING;
-
-static struct hash * strhash = 0;
-static int strtotal = 0;
-static int strcount_in = 0;
-static int strcount_out = 0;
-
-
-/*
- * Immortal string allocator implementation speeds string allocation and cuts
- * down on internal fragmentation.
- */
-
-# define STRING_BLOCK 4096
-typedef struct strblock
-{
- struct strblock * next;
- char data[STRING_BLOCK];
-} strblock;
-
-static strblock * strblock_chain = 0;
-
-/* Storage remaining in the current strblock */
-static char * storage_start = 0;
-static char * storage_finish = 0;
-
-
-/*
- * allocate() - Allocate n bytes of immortal string storage.
- */
-
-static char * allocate( size_t const n )
-{
-#ifdef BJAM_NEWSTR_NO_ALLOCATE
- return (char*)BJAM_MALLOC_ATOMIC(n);
-#else
- /* See if we can grab storage from an existing block. */
- size_t remaining = storage_finish - storage_start;
- if ( remaining >= n )
- {
- char * result = storage_start;
- storage_start += n;
- return result;
- }
- else /* Must allocate a new block. */
- {
- strblock * new_block;
- size_t nalloc = n;
- if ( nalloc < STRING_BLOCK )
- nalloc = STRING_BLOCK;
-
- /* Allocate a new block and link into the chain. */
- new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
- if ( new_block == 0 )
- return 0;
- new_block->next = strblock_chain;
- strblock_chain = new_block;
-
- /* Take future allocations out of the larger remaining space. */
- if ( remaining < nalloc - n )
- {
- storage_start = new_block->data + n;
- storage_finish = new_block->data + nalloc;
- }
- return new_block->data;
- }
-#endif
-}
-
-
-/*
- * newstr() - return a dynamically allocated copy of a string.
- */
-
-char * newstr( char * string )
-{
- STRING str;
- STRING * s = &str;
-
- if ( !strhash )
- strhash = hashinit( sizeof( STRING ), "strings" );
-
- *s = string;
-
- if ( hashenter( strhash, (HASHDATA **)&s ) )
- {
- int l = strlen( string );
- char * m = (char *)allocate( l + 1 );
-
- strtotal += l + 1;
- memcpy( m, string, l + 1 );
- *s = m;
- }
-
- strcount_in += 1;
- return *s;
-}
-
-
-/*
- * copystr() - return a copy of a string previously returned by newstr()
- */
-
-char * copystr( char * s )
-{
- strcount_in += 1;
- return s;
-}
-
-
-/*
- * freestr() - free a string returned by newstr() or copystr()
- */
-
-void freestr( char * s )
-{
- strcount_out += 1;
-}
-
-
-/*
- * str_done() - free string tables.
- */
-
-void str_done()
-{
- /* Reclaim string blocks. */
- while ( strblock_chain != 0 )
- {
- strblock * n = strblock_chain->next;
- BJAM_FREE(strblock_chain);
- strblock_chain = n;
- }
-
- hashdone( strhash );
-
- if ( DEBUG_MEM )
- printf( "%dK in strings\n", strtotal / 1024 );
-
- /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
-}
diff --git a/tools/build/v2/engine/newstr.h b/tools/build/v2/engine/newstr.h
deleted file mode 100644
index 84a4d7b6da..0000000000
--- a/tools/build/v2/engine/newstr.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * newstr.h - string manipulation routines
- */
-
-char * copystr ( char * );
-void freestr ( char * );
-char * newstr ( char * );
-void str_done();
diff --git a/tools/build/v2/engine/object.c b/tools/build/v2/engine/object.c
new file mode 100644
index 0000000000..399f04ae84
--- /dev/null
+++ b/tools/build/v2/engine/object.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "object.h"
+# include <stddef.h>
+# include <stdlib.h>
+# include <assert.h>
+
+/*
+ * object.c - object manipulation routines
+ *
+ * External functions:
+ *
+ * object_new() - create an object from a string
+ * object_copy() - return a copy of an object
+ * object_free() - free an object
+ * object_str() - get the string value of an object
+ * object_done() - free string tables
+ *
+ * This implementation builds a hash table of all strings, so that multiple
+ * calls of object_new() on the same string allocate memory for the string once.
+ * Strings are never actually freed.
+ */
+
+#define OBJECT_MAGIC 0xa762e0e3u
+
+#ifndef object_copy
+
+struct hash_header
+{
+#ifndef NDEBUG
+ unsigned int magic;
+#endif
+ unsigned int hash;
+ struct hash_item * next;
+};
+
+#endif
+
+struct hash_item
+{
+ struct hash_header header;
+ char data[1];
+};
+
+#define ALLOC_ALIGNMENT ( sizeof( struct hash_item ) - sizeof( struct hash_header ) )
+
+typedef struct string_set
+{
+ unsigned int num;
+ unsigned int size;
+ struct hash_item * * data;
+} string_set;
+
+static string_set strhash;
+static int strtotal = 0;
+static int strcount_in = 0;
+static int strcount_out = 0;
+
+
+/*
+ * Immortal string allocator implementation speeds string allocation and cuts
+ * down on internal fragmentation.
+ */
+
+# define STRING_BLOCK 4096
+typedef struct strblock
+{
+ struct strblock * next;
+ char data[STRING_BLOCK];
+} strblock;
+
+static strblock * strblock_chain = 0;
+
+/* Storage remaining in the current strblock */
+static char * storage_start = 0;
+static char * storage_finish = 0;
+
+
+/*
+ * allocate() - Allocate n bytes of immortal string storage.
+ */
+
+static char * allocate( size_t n )
+{
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+ return (char*)BJAM_MALLOC(n);
+#else
+ /* See if we can grab storage from an existing block. */
+ size_t remaining = storage_finish - storage_start;
+ n = ((n + ALLOC_ALIGNMENT - 1) / ALLOC_ALIGNMENT) * ALLOC_ALIGNMENT;
+ if ( remaining >= n )
+ {
+ char * result = storage_start;
+ storage_start += n;
+ return result;
+ }
+ else /* Must allocate a new block. */
+ {
+ strblock * new_block;
+ size_t nalloc = n;
+ if ( nalloc < STRING_BLOCK )
+ nalloc = STRING_BLOCK;
+
+ /* Allocate a new block and link into the chain. */
+ new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
+ if ( new_block == 0 )
+ return 0;
+ new_block->next = strblock_chain;
+ strblock_chain = new_block;
+
+ /* Take future allocations out of the larger remaining space. */
+ if ( remaining < nalloc - n )
+ {
+ storage_start = new_block->data + n;
+ storage_finish = new_block->data + nalloc;
+ }
+ return new_block->data;
+ }
+#endif
+}
+
+static unsigned int hash_keyval( const char * key )
+{
+ unsigned int hash = 0;
+ unsigned i;
+ unsigned int len = strlen( key );
+
+ for ( i = 0; i < len / sizeof( unsigned int ); ++i )
+ {
+ unsigned int val;
+ memcpy( &val, key, sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ key += sizeof( unsigned int );
+ }
+
+ {
+ unsigned int val = 0;
+ memcpy( &val, key, len % sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ }
+
+ hash += (hash >> 17);
+
+ return hash;
+}
+
+static void string_set_init(string_set * set)
+{
+ set->size = 0;
+ set->num = 4;
+ set->data = (struct hash_item * *)BJAM_MALLOC( set->num * sizeof( struct hash_item * ) );
+ memset( set->data, 0, set->num * sizeof( struct hash_item * ) );
+}
+
+static void string_set_done(string_set * set)
+{
+ BJAM_FREE( set->data );
+}
+
+static void string_set_resize(string_set *set)
+{
+ unsigned i;
+ string_set new_set;
+ new_set.num = set->num * 2;
+ new_set.size = set->size;
+ new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item * ) * new_set.num );
+ memset(new_set.data, 0, sizeof(struct hash_item *) * new_set.num);
+ for ( i = 0; i < set->num; ++i )
+ {
+ while ( set->data[i] )
+ {
+ struct hash_item * temp = set->data[i];
+ unsigned pos = temp->header.hash % new_set.num;
+ set->data[i] = temp->header.next;
+ temp->header.next = new_set.data[pos];
+ new_set.data[pos] = temp;
+ }
+ }
+ BJAM_FREE( set->data );
+ *set = new_set;
+}
+
+static const char * string_set_insert ( string_set * set, const char * string )
+{
+ unsigned hash = hash_keyval( string );
+ unsigned pos = hash % set->num;
+ unsigned l;
+
+ struct hash_item * result;
+
+ for ( result = set->data[pos]; result; result = result->header.next )
+ {
+ if ( strcmp( result->data, string ) == 0 )
+ {
+ return result->data;
+ }
+ }
+
+ if( set->size >= set->num )
+ {
+ string_set_resize( set );
+ pos = hash % set->num;
+ }
+
+ l = strlen( string );
+ result = (struct hash_item *)allocate( sizeof( struct hash_header ) + l + 1 );
+ result->header.hash = hash;
+ result->header.next = set->data[pos];
+#ifndef NDEBUG
+ result->header.magic = OBJECT_MAGIC;
+#endif
+ memcpy( result->data, string, l + 1 );
+ assert( hash_keyval( result->data ) == result->header.hash );
+ set->data[pos] = result;
+ strtotal += l + 1;
+ ++set->size;
+
+ return result->data;
+}
+
+
+static struct hash_item * object_get_item( OBJECT * obj )
+{
+ return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data ) );
+}
+
+
+static void object_validate( OBJECT * obj )
+{
+ assert( object_get_item( obj )->header.magic == OBJECT_MAGIC );
+}
+
+
+/*
+ * object_new() - create an object from a string.
+ */
+
+OBJECT * object_new( const char * string )
+{
+#ifdef BJAM_NO_MEM_CACHE
+ int l = strlen( string );
+ struct hash_item * m = (struct hash_item *)BJAM_MALLOC( sizeof(struct hash_header) + l + 1 );
+
+ strtotal += l + 1;
+ memcpy( m->data, string, l + 1 );
+ m->header.magic = OBJECT_MAGIC;
+ return (OBJECT *)m->data;
+#else
+ if ( ! strhash.data )
+ string_set_init( &strhash );
+
+ strcount_in += 1;
+
+ return (OBJECT *)string_set_insert( &strhash, string );
+#endif
+}
+
+#ifndef object_copy
+
+/*
+ * object_copy() - return a copy of an object
+ */
+
+OBJECT * object_copy( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return object_new( object_str( obj ) );
+#else
+ strcount_in += 1;
+ return obj;
+#endif
+}
+
+
+/*
+ * object_free() - free an object
+ */
+
+void object_free( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ BJAM_FREE( object_get_item( obj ) );
+#endif
+ strcount_out += 1;
+}
+
+
+/*
+ * object_str() - return the
+ */
+
+const char * object_str( OBJECT * obj )
+{
+ object_validate( obj );
+ return (const char *)obj;
+}
+
+
+/*
+ * object_equal() - compare two objects
+ */
+
+int object_equal( OBJECT * lhs, OBJECT * rhs )
+{
+ object_validate( lhs );
+ object_validate( rhs );
+#ifdef BJAM_NO_MEM_CACHE
+ return strcmp(object_str(lhs), object_str(rhs)) == 0;
+#else
+ assert( (lhs == rhs) == ( strcmp(object_str(lhs), object_str(rhs)) == 0 ) );
+ return lhs == rhs;
+#endif
+}
+
+
+/*
+ * object_hash() - returns the hash value of an object
+ */
+
+unsigned int object_hash( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return hash_keyval( object_str( obj ) );
+#else
+ return object_get_item( obj )->header.hash;
+#endif
+}
+
+#endif
+
+/*
+ * object_done() - free string tables.
+ */
+
+void object_done()
+{
+
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+
+ unsigned i;
+
+ for ( i = 0; i < strhash.num; ++i )
+ {
+ while ( strhash.data[i] )
+ {
+ struct hash_item * item = strhash.data[i];
+ strhash.data[i] = item->header.next;
+ BJAM_FREE( item );
+ }
+ }
+
+#else
+
+ /* Reclaim string blocks. */
+ while ( strblock_chain != 0 )
+ {
+ strblock * n = strblock_chain->next;
+ BJAM_FREE(strblock_chain);
+ strblock_chain = n;
+ }
+
+#endif
+
+ string_set_done( &strhash );
+
+ if ( DEBUG_MEM )
+ printf( "%dK in strings\n", strtotal / 1024 );
+
+ /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
+}
diff --git a/tools/build/v2/engine/object.h b/tools/build/v2/engine/object.h
new file mode 100644
index 0000000000..1c123f8b0f
--- /dev/null
+++ b/tools/build/v2/engine/object.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * object.h - object manipulation routines
+ */
+
+#ifndef BOOST_JAM_OBJECT_H
+#define BOOST_JAM_OBJECT_H
+
+typedef struct _object OBJECT;
+
+OBJECT * object_new ( const char * );
+void object_done ( void );
+
+#if defined(NDEBUG) && !defined(BJAM_NO_MEM_CACHE)
+
+struct hash_header
+{
+ unsigned int hash;
+ struct hash_item * next;
+};
+
+#define object_str( obj ) ( (const char *)( obj ) )
+#define object_copy( obj ) ( obj )
+#define object_free( obj ) ( (void)0 )
+#define object_equal( lhs, rhs ) ( ( lhs ) == ( rhs ) )
+#define object_hash( obj ) ( ((struct hash_header *)( (char *)( obj ) - sizeof(struct hash_header) ))->hash )
+
+#else
+
+const char * object_str ( OBJECT * );
+OBJECT * object_copy ( OBJECT * );
+void object_free ( OBJECT * );
+int object_equal ( OBJECT *, OBJECT * );
+unsigned int object_hash ( OBJECT * );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/output.c b/tools/build/v2/engine/output.c
index 483c6ca9e6..a0154c6ea3 100644
--- a/tools/build/v2/engine/output.c
+++ b/tools/build/v2/engine/output.c
@@ -6,7 +6,7 @@
#include "jam.h"
#include "output.h"
-#include "newstr.h"
+#include "object.h"
#include <stdio.h>
#define bjam_out (stdout)
@@ -101,25 +101,25 @@ void out_action
}
-char * outf_int( int value )
+OBJECT * outf_int( int value )
{
char buffer[50];
sprintf( buffer, "%i", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_double( double value )
+OBJECT * outf_double( double value )
{
char buffer[50];
sprintf( buffer, "%f", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_time( time_t value )
+OBJECT * outf_time( time_t value )
{
char buffer[50];
strftime( buffer, 49, "%Y-%m-%d %H:%M:%SZ", gmtime( &value ) );
- return newstr( buffer );
+ return object_new( buffer );
}
diff --git a/tools/build/v2/engine/output.h b/tools/build/v2/engine/output.h
index 9e9876cfc5..64175e67ef 100644
--- a/tools/build/v2/engine/output.h
+++ b/tools/build/v2/engine/output.h
@@ -7,6 +7,7 @@
#ifndef BJAM_OUTPUT_H
#define BJAM_OUTPUT_H
+#include "object.h"
#include <time.h>
#define EXIT_OK 0
@@ -22,8 +23,8 @@ void out_action(
int exit_reason
);
-char * outf_int( int value );
-char * outf_double( double value );
-char * outf_time( time_t value );
+OBJECT * outf_int( int value );
+OBJECT * outf_double( double value );
+OBJECT * outf_time( time_t value );
#endif
diff --git a/tools/build/v2/engine/parse.c b/tools/build/v2/engine/parse.c
index 9114fa057a..167ad1745a 100644
--- a/tools/build/v2/engine/parse.c
+++ b/tools/build/v2/engine/parse.c
@@ -14,9 +14,10 @@
#include "lists.h"
#include "parse.h"
#include "scan.h"
-#include "newstr.h"
+#include "object.h"
#include "modules.h"
#include "frames.h"
+#include "function.h"
/*
* parse.c - make and destroy parse trees as driven by the parser
@@ -29,7 +30,7 @@
static PARSE * yypsave;
-void parse_file( char * f, FRAME * frame )
+void parse_file( OBJECT * f, FRAME * frame )
{
/* Suspend scan of current file and push this new file in the stream. */
yyfparse( f );
@@ -41,6 +42,7 @@ void parse_file( char * f, FRAME * frame )
for ( ; ; )
{
PARSE * p;
+ FUNCTION * func;
/* Filled by yyparse() calling parse_save(). */
yypsave = 0;
@@ -50,8 +52,10 @@ void parse_file( char * f, FRAME * frame )
break;
/* Run the parse tree. */
- parse_evaluate( p, frame );
+ func = function_compile( p );
parse_free( p );
+ list_free( function_run( func, frame, stack_global() ) );
+ function_free( func );
}
}
@@ -63,17 +67,17 @@ void parse_save( PARSE * p )
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num )
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num )
{
PARSE * p = (PARSE *)BJAM_MALLOC( sizeof( PARSE ) );
- p->func = func;
+ p->type = type;
p->left = left;
p->right = right;
p->third = third;
@@ -85,12 +89,13 @@ PARSE * parse_make(
if ( left )
{
- p->file = left->file;
+ p->file = object_copy( left->file );
p->line = left->line;
}
else
{
yyinput_stream( &p->file, &p->line );
+ p->file = object_copy( p->file );
}
return p;
@@ -109,9 +114,9 @@ void parse_free( PARSE * p )
return;
if ( p->string )
- freestr( p->string );
+ object_free( p->string );
if ( p->string1 )
- freestr( p->string1 );
+ object_free( p->string1 );
if ( p->left )
parse_free( p->left );
if ( p->right )
@@ -119,14 +124,9 @@ void parse_free( PARSE * p )
if ( p->third )
parse_free( p->third );
if ( p->rulename )
- freestr( p->rulename );
+ object_free( p->rulename );
+ if ( p->file )
+ object_free( p->file );
BJAM_FREE( (char *)p );
}
-
-
-LIST * parse_evaluate( PARSE * p, FRAME * frame )
-{
- frame->procedure = p;
- return (*p->func)( p, frame );
-}
diff --git a/tools/build/v2/engine/parse.h b/tools/build/v2/engine/parse.h
index e324972f7b..882a029f42 100644
--- a/tools/build/v2/engine/parse.h
+++ b/tools/build/v2/engine/parse.h
@@ -21,36 +21,55 @@
* parse.h - make and destroy parse trees as driven by the parser.
*/
+#define PARSE_APPEND 0
+#define PARSE_FOREACH 1
+#define PARSE_IF 2
+#define PARSE_EVAL 3
+#define PARSE_INCLUDE 4
+#define PARSE_LIST 5
+#define PARSE_LOCAL 6
+#define PARSE_MODULE 7
+#define PARSE_CLASS 8
+#define PARSE_NULL 9
+#define PARSE_ON 10
+#define PARSE_RULE 11
+#define PARSE_RULES 12
+#define PARSE_SET 13
+#define PARSE_SETCOMP 14
+#define PARSE_SETEXEC 15
+#define PARSE_SETTINGS 16
+#define PARSE_SWITCH 17
+#define PARSE_WHILE 18
+
/*
* Parse tree node.
*/
struct _PARSE {
- LIST * (* func)( PARSE *, FRAME * );
+ int type;
PARSE * left;
PARSE * right;
PARSE * third;
- char * string;
- char * string1;
+ OBJECT * string;
+ OBJECT * string1;
int num;
int refs;
-/* module * module; */
- char * rulename;
- char * file;
+ OBJECT * rulename;
+ OBJECT * file;
int line;
};
-void parse_file( char *, FRAME * );
+void parse_file( OBJECT *, FRAME * );
void parse_save( PARSE * );
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num );
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num );
void parse_refer ( PARSE * );
void parse_free ( PARSE * );
diff --git a/tools/build/v2/engine/patchlevel.h b/tools/build/v2/engine/patchlevel.h
index 699efd84ba..18224c1c31 100644
--- a/tools/build/v2/engine/patchlevel.h
+++ b/tools/build/v2/engine/patchlevel.h
@@ -8,10 +8,10 @@
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
#define VERSION_MAJOR 2011
-#define VERSION_MINOR 04
+#define VERSION_MINOR 12
#define VERSION_PATCH 0
#define VERSION_MAJOR_SYM "2011"
-#define VERSION_MINOR_SYM "04"
+#define VERSION_MINOR_SYM "12"
#define VERSION_PATCH_SYM "00"
-#define VERSION "2011.4"
-#define JAMVERSYM "JAMVERSION=2011.4"
+#define VERSION "2011.12"
+#define JAMVERSYM "JAMVERSION=2011.12"
diff --git a/tools/build/v2/engine/pathmac.c b/tools/build/v2/engine/pathmac.c
deleted file mode 100644
index e2c250e338..0000000000
--- a/tools/build/v2/engine/pathmac.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-# define DELIM ':'
-
-/*
- * pathunix.c - manipulate file names on UNIX, NT, OS2
- *
- * External routines:
- *
- * path_parse() - split a file name into dir/base/suffix/member
- * path_build() - build a filename given dir/base/suffix/member
- * path_parent() - make a PATHNAME point to its parent dir
- *
- * File_parse() and path_build() just manipuate a string and a structure;
- * they do not make system calls.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
- * 12/19/94 (mikem) - solaris string table insanity support
- * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
- * should expect hdr searches to come up with strings
- * like "thing/thing.h". So we need to test for "/" as
- * well as "\" when parsing pathnames.
- * 03/16/95 (seiwald) - fixed accursed typo on line 69.
- * 05/03/96 (seiwald) - split from filent.c, fileunix.c
- * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
- * don't include the archive member name.
- * 01/10/01 (seiwald) - path_parse now strips the trailing : from the
- * directory name, unless the directory name is all
- * :'s, so that $(d:P) works.
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member
- */
-
-void
-path_parse(
- char *file,
- PATHNAME *f )
-{
- char *p, *q;
- char *end;
-
- memset( (char *)f, 0, sizeof( *f ) );
-
- /* Look for <grist> */
-
- if ( file[0] == '<' && ( p = strchr( file, '>' ) ) )
- {
- f->f_grist.ptr = file;
- f->f_grist.len = p - file;
- file = p + 1;
- }
-
- /* Look for dir: */
-
- if ( p = strrchr( file, DELIM ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p - file;
- file = p + 1;
-
- /* All :'s? Include last : as part of directory name */
-
- while ( ( p > f->f_dir.ptr ) && ( *--p == DELIM ) );
-
- if ( p == f->f_dir.ptr )
- ++f->f_dir.len;
- }
-
- end = file + strlen( file );
-
- /* Look for (member). */
-
- if ( ( p = strchr( file, '(' ) ) && ( end[-1] == ')' ) )
- {
- f->f_member.ptr = p + 1;
- f->f_member.len = end - p - 2;
- end = p;
- }
-
- /* Look for .suffix */
- /* This would be memrchr() */
-
- p = 0;
- q = file;
-
- while ( q = memchr( q, '.', end - q ) )
- p = q++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base */
-
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-}
-
-/*
- * path_build() - build a filename given dir/base/suffix/member.
- */
-
-# define DIR_EMPTY 0 /* "" */
-# define DIR_DOT 1 /* : */
-# define DIR_DOTDOT 2 /* :: */
-# define DIR_ABS 3 /* dira:dirb: */
-# define DIR_REL 4 /* :dira:dirb: */
-
-# define G_DIR 0 /* take dir */
-# define G_ROOT 1 /* take root */
-# define G_CAT 2 /* prepend root to dir */
-# define G_DTDR 3 /* :: of rel dir */
-# define G_DDDD 4 /* make it ::: (../..) */
-# define G_MT 5 /* leave it empty */
-
-char grid[5][5] = {
-/* EMPTY DOT DOTDOT ABS REL */
-/* EMPTY */ { G_MT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOT */ { G_ROOT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOTDOT */ { G_ROOT, G_ROOT, G_DDDD, G_DIR, G_DTDR },
-/* ABS */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT },
-/* REL */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT }
-};
-
-static int file_flags( char * ptr, int len )
-{
- if ( !len )
- return DIR_EMPTY;
- if ( ( len == 1 ) && ( ptr[0] == DELIM ) )
- return DIR_DOT;
- if ( ( len == 2 ) && ( ptr[0] == DELIM ) && ( ptr[1] == DELIM ) )
- return DIR_DOTDOT;
- if ( ptr[0] == DELIM )
- return DIR_REL;
- return DIR_ABS;
-}
-
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- int dflag;
- int rflag;
- int act;
-
- file_build1( f, file );
-
- /* Combine root & directory, according to the grid. */
-
- dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
- rflag = file_flags( f->f_root.ptr, f->f_root.len );
-
- switch ( act = grid[ rflag ][ dflag ] )
- {
- case G_DTDR:
- {
- /* :: of rel dir */
- string_push_back( file, DELIM );
- }
- /* fall through */
-
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_CAT:
- /* prepend root to dir */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- if ( file->value[ file->size - 1 ] == DELIM )
- string_pop_back( file );
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_DDDD:
- /* make it ::: (../..) */
- string_append( file, ":::" );
- break;
- }
-
- /* Put : between dir and file (if none already). */
-
- if ( ( act != G_MT ) &&
- ( file->value[ file->size - 1 ] != DELIM ) &&
- ( f->f_base.len || f->f_suffix.len ) )
- {
- string_push_back( file, DELIM );
- }
-
- if ( f->f_base.len )
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
-
- if ( f->f_suffix.len )
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
-
- if ( f->f_member.len )
- {
- string_push_back( file, '(' );
- string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
- string_push_back( file, ')' );
- }
-
- if ( DEBUG_SEARCH )
- printf( " -> '%s'\n", file->value );
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-void path_parent( PATHNAME * f )
-{
- /* Just set everything else to nothing. */
-
- f->f_base.ptr =
- f->f_suffix.ptr =
- f->f_member.ptr = "";
-
- f->f_base.len =
- f->f_suffix.len =
- f->f_member.len = 0;
-}
-
-# endif /* OS_MAC */
diff --git a/tools/build/v2/engine/pathsys.h b/tools/build/v2/engine/pathsys.h
index 737758105f..978dbf4a7a 100644
--- a/tools/build/v2/engine/pathsys.h
+++ b/tools/build/v2/engine/pathsys.h
@@ -15,31 +15,27 @@
* have the same name: it never appears in the bound name of a target.
* (member) is an archive member name: the syntax is arbitrary, but must
* agree in path_parse(), path_build() and the Jambase.
- *
- * On VMS, we keep track of whether the original path was a directory
- * (without a file), so that $(VAR:D) can climb to the parent.
*/
#ifndef PATHSYS_VP_20020211_H
# define PATHSYS_VP_20020211_H
+#include "jam.h"
#include "strings.h"
+#include "object.h"
typedef struct _pathname PATHNAME;
typedef struct _pathpart PATHPART;
struct _pathpart
{
- char * ptr;
- int len;
+ const char * ptr;
+ int len;
};
struct _pathname
{
PATHPART part[6];
-#ifdef OS_VMS
- int parent;
-#endif
#define f_grist part[0]
#define f_root part[1]
@@ -52,18 +48,26 @@ struct _pathname
void path_build( PATHNAME * f, string * file, int binding );
void path_build1( PATHNAME * f, string * file );
-void path_parse( char * file, PATHNAME * f );
+void path_parse( const char * file, PATHNAME * f );
void path_parent( PATHNAME * f );
#ifdef NT
-/** Returns newstr-allocated string with long equivivalent of 'short_name'.
+/** Returns object_new-allocated string with long equivivalent of 'short_name'.
If none exists -- i.e. 'short_path' is already long path, it's returned
unaltered. */
-char * short_path_to_long_path( char * short_path );
+OBJECT * short_path_to_long_path( OBJECT * short_path );
#endif
+/** Given a path, returns an object that can be
+ used as a unique key for that path. Equivalent
+ paths such as a/b, A\B, and a\B on NT all yield the
+ same key.
+ */
+OBJECT * path_as_key( OBJECT * path );
+void path_add_key( OBJECT * path );
+
#ifdef USE_PATHUNIX
/** Returns a static pointer to the system dependent path to the temporary
directory. NOTE: *without* a trailing path separator.
@@ -72,11 +76,11 @@ const char * path_tmpdir( void );
/** Returns a new temporary name.
*/
-const char * path_tmpnam( void );
+OBJECT * path_tmpnam( void );
/** Returns a new temporary path.
*/
-const char * path_tmpfile( void );
+OBJECT * path_tmpfile( void );
#endif
/** Give the first argument to 'main', return a full path to
@@ -86,6 +90,8 @@ const char * path_tmpfile( void );
Implemented in jam.c
*/
-char * executable_path (char *argv0);
+char * executable_path (const char *argv0);
+
+void path_done( void );
#endif
diff --git a/tools/build/v2/engine/pathunix.c b/tools/build/v2/engine/pathunix.c
index 2daad14b72..a8428df8d6 100644
--- a/tools/build/v2/engine/pathunix.c
+++ b/tools/build/v2/engine/pathunix.c
@@ -14,10 +14,11 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include <time.h>
# include <stdlib.h>
+# include <assert.h>
# ifndef OS_NT
# include <unistd.h>
# endif
@@ -56,11 +57,11 @@
* path_parse() - split a file name into dir/base/suffix/member
*/
-void path_parse( char * file, PATHNAME * f )
+void path_parse( const char * file, PATHNAME * f )
{
- char * p;
- char * q;
- char * end;
+ const char * p;
+ const char * q;
+ const char * end;
memset( (char *)f, 0, sizeof( *f ) );
@@ -273,124 +274,250 @@ path_parent( PATHNAME *f )
#ifdef NT
#include <windows.h>
-#include <tchar.h>
/* The definition of this in winnt.h is not ANSI-C compatible. */
#undef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+OBJECT * path_as_key( OBJECT * path );
+static void path_write_key( char * path_, string * out );
-DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
- cchBuffer)
+void ShortPathToLongPath( char * short_path, string * out )
{
- LONG i=0;
- TCHAR path[_MAX_PATH]={0};
- TCHAR ret[_MAX_PATH]={0};
- LONG pos=0, prev_pos=0;
- LONG len=_tcslen(lpszShortPath);
-
- /* Is the string valid? */
- if (!lpszShortPath) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
+ const char * new_element;
+ unsigned long saved_size;
+ char * p;
+
+ if ( short_path[0] == '\0' )
+ {
+ return;
+ }
+
+ if ( short_path[0] == '\\' && short_path[1] == '\0')
+ {
+ string_push_back( out, '\\' );
+ return;
+ }
+
+ if ( short_path[1] == ':' &&
+ ( short_path[2] == '\0' ||
+ ( short_path[2] == '\\' && short_path[3] == '\0' ) ) )
+ {
+ string_push_back( out, toupper( short_path[0] ) );
+ string_push_back( out, ':' );
+ string_push_back( out, '\\' );
+ return;
+ }
+
+ /* '/' already handled. */
+ if ( ( p = strrchr( short_path, '\\' ) ) )
+ {
+ char saved;
+ new_element = p + 1;
+
+ /* special case \ */
+ if ( p == short_path )
+ ++p;
+
+ /* special case D:\ */
+ if ( p == short_path + 2 && short_path[1] == ':' )
+ ++p;
+
+ saved = *p;
+ *p = '\0';
+ path_write_key( short_path, out );
+ *p = saved;
+ }
+ else
+ {
+ new_element = short_path;
+ }
+
+ if ( out->size && out->value[ out->size - 1 ] != '\\' )
+ {
+ string_push_back( out, '\\' );
+ }
+
+ saved_size = out->size;
+ string_append( out, new_element );
+
+ if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
+ new_element[0] == '.' && new_element[1] == '.'
+ && new_element[2] == '\0' ) )
+ {
+ WIN32_FIND_DATA fd;
+ HANDLE hf = 0;
+ hf = FindFirstFile( out->value, &fd );
+
+ /* If the file exists, replace the name. */
+ if ( hf != INVALID_HANDLE_VALUE )
+ {
+ string_truncate( out, saved_size );
+ string_append( out, fd.cFileName );
+ FindClose( hf );
+ }
}
+}
- /* Is the path valid? */
- if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
- return 0;
+OBJECT * short_path_to_long_path( OBJECT * short_path )
+{
+ return path_as_key( short_path );
+}
- /* Convert "/" to "\" */
- for (i=0;i<len;++i) {
- if (lpszShortPath[i]==_T('/'))
- path[i]=_T('\\');
+struct path_key_entry
+{
+ OBJECT * path;
+ OBJECT * key;
+};
+
+static struct hash * path_key_cache;
+
+static void path_write_key( char * path_, string * out )
+{
+ struct path_key_entry * result;
+ OBJECT * path = object_new( path_ );
+ int found;
+
+ /* This is only called by path_as_key, which initializes the cache. */
+ assert( path_key_cache );
+
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ /* path_ is already normalized. */
+ result->path = path;
+ ShortPathToLongPath( path_, out );
+ result->key = object_new( out->value );
+ }
+ else
+ {
+ object_free( path );
+ string_append( out, object_str( result->key ) );
+ }
+
+}
+
+static void normalize_path( string * path )
+{
+ char * s;
+ for ( s = path->value; s < path->value + path->size; ++s )
+ {
+ if ( *s == '/' )
+ *s = '\\';
else
- path[i]=lpszShortPath[i];
+ *s = tolower( *s );
+ }
+ /* Strip trailing "/" */
+ if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' )
+ {
+ string_pop_back( path );
}
+}
- /* UNC path? */
- if (path[0]==_T('\\') && path[1]==_T('\\')) {
- pos=2;
- for (i=0;i<2;++i) {
- while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
- ++pos;
- ++pos;
+void path_add_key( OBJECT * path )
+{
+ struct path_key_entry * result;
+ int found;
+
+ if ( ! path_key_cache )
+ path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
+
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ string buf[1];
+ OBJECT * normalized;
+ struct path_key_entry * nresult;
+ result->path = path;
+ string_copy( buf, object_str( path ) );
+ normalize_path( buf );
+ normalized = object_new( buf->value );
+ string_free( buf );
+ nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+ if ( !found || nresult == result )
+ {
+ nresult->path = object_copy( normalized );
+ nresult->key = object_copy( path );
}
- _tcsncpy(ret,path,pos-1);
- } /* Drive letter? */
- else if (path[1]==_T(':')) {
- if (path[2]==_T('\\'))
- pos=3;
- if (len==3) {
- if (cchBuffer>3)
- _tcscpy(lpszLongPath,lpszShortPath);
- return len;
+ object_free( normalized );
+ if ( nresult != result )
+ {
+ result->path = object_copy( path );
+ result->key = object_copy( nresult->key );
}
- _tcsncpy(ret,path,2);
}
+}
+
+OBJECT * path_as_key( OBJECT * path )
+{
+ struct path_key_entry * result;
+ int found;
+
+ if ( ! path_key_cache )
+ path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
- /* Expand the path for each subpath, and strip trailing backslashes */
- for (prev_pos = pos-1;pos<=len;++pos) {
- if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
- path[pos-1]!=_T('\\'))) {
- WIN32_FIND_DATA fd;
- HANDLE hf=0;
- TCHAR c=path[pos];
- char* new_element;
- path[pos]=_T('\0');
-
- /* the path[prev_pos+1]... path[pos] range is the part of
- path we're handling right now. We need to find long
- name for that element and add it. */
- new_element = path + prev_pos + 1;
-
- /* First add separator, but only if there's something in result already. */
- if (ret[0] != _T('\0'))
- {
- _tcscat(ret,_T("\\"));
- }
-
- /* If it's ".." element, we need to append it, not
- the name in parent that FindFirstFile will return.
- Same goes for "." */
-
- if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
- new_element[0] == _T('.') && new_element[1] == _T('.')
- && new_element[2] == _T('\0'))
- {
- _tcscat(ret, new_element);
- }
- else
- {
- hf=FindFirstFile(path, &fd);
- if (hf==INVALID_HANDLE_VALUE)
- return 0;
-
- _tcscat(ret,fd.cFileName);
- FindClose(hf);
- }
-
- path[pos]=c;
-
- prev_pos = pos;
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ string buf[1];
+ OBJECT * normalized;
+ struct path_key_entry * nresult;
+ result->path = path;
+ string_copy( buf, object_str( path ) );
+ normalize_path( buf );
+ normalized = object_new( buf->value );
+ nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+ if ( !found || nresult == result )
+ {
+ string long_path[1];
+ nresult->path = normalized;
+ string_new( long_path );
+ ShortPathToLongPath( buf->value, long_path );
+ nresult->path = object_copy( normalized );
+ nresult->key = object_new( long_path->value );
+ string_free( long_path );
}
+ string_free( buf );
+ object_free( normalized );
+ if ( nresult != result )
+ {
+ result->path = object_copy( path );
+ result->key = object_copy( nresult->key );
+ }
+ }
+
+ return object_copy( result->key );
+}
+
+static void free_path_key_entry( void * xentry, void * data )
+{
+ struct path_key_entry * entry = (struct path_key_entry *)xentry;
+ object_free( entry->path );
+ object_free( entry->key );
+}
+
+void path_done( void )
+{
+ if ( path_key_cache )
+ {
+ hashenumerate( path_key_cache, &free_path_key_entry, (void *)0 );
+ hashdone( path_key_cache );
}
+}
- len=_tcslen(ret)+1;
- if (cchBuffer>=len)
- _tcscpy(lpszLongPath,ret);
+#else
- return len;
+void path_add_key( OBJECT * path )
+{
}
-char* short_path_to_long_path(char* short_path)
+OBJECT * path_as_key( OBJECT * path )
{
- char buffer2[_MAX_PATH];
- int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH);
+ return object_copy( path );
+}
- if (ret)
- return newstr(buffer2);
- else
- return newstr(short_path);
+void path_done( void )
+{
}
#endif
@@ -424,7 +551,7 @@ const char * path_tmpdir()
return path_tmpdir_result;
}
-const char * path_tmpnam(void)
+OBJECT * path_tmpnam(void)
{
char name_buffer[64];
# ifdef OS_NT
@@ -436,18 +563,21 @@ const char * path_tmpnam(void)
if (0 == c1) c1 = time(0)&0xffff;
c1 += 1;
sprintf(name_buffer,"jam%lx%lx.000",c0,c1);
- return newstr(name_buffer);
+ return object_new(name_buffer);
}
-const char * path_tmpfile(void)
+OBJECT * path_tmpfile(void)
{
- const char * result = 0;
+ OBJECT * result = 0;
+ OBJECT * tmpnam;
string file_path;
string_copy(&file_path,path_tmpdir());
string_push_back(&file_path,PATH_DELIM);
- string_append(&file_path,path_tmpnam());
- result = newstr(file_path.value);
+ tmpnam = path_tmpnam();
+ string_append(&file_path,object_str(tmpnam));
+ object_free(tmpnam);
+ result = object_new(file_path.value);
string_free(&file_path);
return result;
diff --git a/tools/build/v2/engine/pathvms.c b/tools/build/v2/engine/pathvms.c
deleted file mode 100644
index 975fe5a579..0000000000
--- a/tools/build/v2/engine/pathvms.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-# define DEBUG
-
-/*
- * pathvms.c - manipulate file names on VMS
- *
- * External routines:
- *
- * path_parse() - split a file name into dir/base/suffix/member
- * path_build() - build a filename given dir/base/suffix/member
- * path_parent() - make a PATHNAME point to its parent dir
- *
- * File_parse() and path_build() just manipuate a string and a structure;
- * they do not make system calls.
- *
- * WARNING! This file contains voodoo logic, as black magic is
- * necessary for wrangling with VMS file name. Woe be to people
- * who mess with this code.
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split from filevms.c
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member.
- */
-
-void path_parse( char * file, PATHNAME * f )
-{
- char * p;
- char * q;
- char * end;
-
- memset( (char *)f, 0, sizeof( *f ) );
-
- /* Look for <grist> */
-
- if ( ( file[0] == '<' ) && ( p = strchr( file, '>' ) ) )
- {
- f->f_grist.ptr = file;
- f->f_grist.len = p - file;
- file = p + 1;
- }
-
- /* Look for dev:[dir] or dev: */
-
- if ( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p + 1 - file;
- file = p + 1;
- }
-
- end = file + strlen( file );
-
- /* Look for (member). */
-
- if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) )
- {
- f->f_member.ptr = p + 1;
- f->f_member.len = end - p - 2;
- end = p;
- }
-
- /* Look for .suffix */
- /* This would be memrchr(). */
-
- p = 0;
- q = file;
-
- while ( q = (char *)memchr( q, '.', end - q ) )
- p = q++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base. */
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-
- /* Is this a directory without a file spec? */
- f->parent = 0;
-}
-
-/*
- * dir mods result
- * --- --- ------
- * Rerooting:
- *
- * (none) :R=dev: dev:
- * devd: :R=dev: devd:
- * devd:[dir] :R=dev: devd:[dir]
- * [.dir] :R=dev: dev:[dir] questionable
- * [dir] :R=dev: dev:[dir]
- *
- * (none) :R=[rdir] [rdir] questionable
- * devd: :R=[rdir] devd:
- * devd:[dir] :R=[rdir] devd:[dir]
- * [.dir] :R=[rdir] [rdir.dir] questionable
- * [dir] :R=[rdir] [rdir]
- *
- * (none) :R=dev:[root] dev:[root]
- * devd: :R=dev:[root] devd:
- * devd:[dir] :R=dev:[root] devd:[dir]
- * [.dir] :R=dev:[root] dev:[root.dir]
- * [dir] :R=dev:[root] [dir]
- *
- * Climbing to parent:
- *
- */
-
-# define DIR_EMPTY 0 /* empty string */
-# define DIR_DEV 1 /* dev: */
-# define DIR_DEVDIR 2 /* dev:[dir] */
-# define DIR_DOTDIR 3 /* [.dir] */
-# define DIR_DASHDIR 4 /* [-] or [-.dir] */
-# define DIR_ABSDIR 5 /* [dir] */
-# define DIR_ROOT 6 /* [000000] or dev:[000000] */
-
-# define G_DIR 0 /* take just dir */
-# define G_ROOT 1 /* take just root */
-# define G_VAD 2 /* root's dev: + [abs] */
-# define G_DRD 3 /* root's dev:[dir] + [.rel] */
-# define G_VRD 4 /* root's dev: + [.rel] made [abs] */
-# define G_DDD 5 /* root's dev:[dir] + . + [dir] */
-
-static int grid[7][7] = {
-
-/* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */
-/* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR,
-/* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD,
-/* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD,
-/* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR,
-/* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR,
-
-};
-
-struct dirinf
-{
- int flags;
-
- struct
- {
- char * ptr;
- int len;
- } dev, dir;
-};
-
-static char * strnchr( char * buf, int c, int len )
-{
- while ( len-- )
- if ( *buf && ( *buf++ == c ) )
- return buf - 1;
- return 0;
-}
-
-
-static void dir_flags( char * buf, int len, struct dirinf * i )
-{
- char * p;
-
- if ( !buf || !len )
- {
- i->flags = DIR_EMPTY;
- i->dev.ptr =
- i->dir.ptr = 0;
- i->dev.len =
- i->dir.len = 0;
- }
- else if ( p = strnchr( buf, ':', len ) )
- {
- i->dev.ptr = buf;
- i->dev.len = p + 1 - buf;
- i->dir.ptr = buf + i->dev.len;
- i->dir.len = len - i->dev.len;
- i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV;
- }
- else
- {
- i->dev.ptr = buf;
- i->dev.len = 0;
- i->dir.ptr = buf;
- i->dir.len = len;
-
- if ( ( *buf == '[' ) && ( buf[1] == ']' ) )
- i->flags = DIR_EMPTY;
- else if ( ( *buf == '[' ) && ( buf[1] == '.' ) )
- i->flags = DIR_DOTDIR;
- else if ( ( *buf == '[' ) && ( buf[1] == '-' ) )
- i->flags = DIR_DASHDIR;
- else
- i->flags = DIR_ABSDIR;
- }
-
- /* But if its rooted in any way. */
-
- if ( ( i->dir.len == 8 ) && !strncmp( i->dir.ptr, "[000000]", 8 ) )
- i->flags = DIR_ROOT;
-}
-
-
-/*
- * path_build() - build a filename given dir/base/suffix/member
- */
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- struct dirinf root;
- struct dirinf dir;
- int g;
-
- file_build1( f, file );
-
- /* Get info on root and dir for combining. */
- dir_flags( f->f_root.ptr, f->f_root.len, &root );
- dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );
-
- /* Combine. */
- switch ( g = grid[ root.flags ][ dir.flags ] )
- {
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_VAD:
- /* root's dev + abs directory */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len );
- break;
-
- case G_DRD:
- case G_DDD:
- /* root's dev:[dir] + rel directory */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
-
- /* sanity checks: root ends with ] */
-
- if ( file->value[file->size - 1] == ']' )
- string_pop_back( file );
-
- /* Add . if separating two -'s */
-
- if ( g == G_DDD )
- string_push_back( file, '.' );
-
- /* skip [ of dir */
- string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 );
- break;
-
- case G_VRD:
- /* root's dev + rel directory made abs */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_push_back( file, '[' );
- /* skip [. of rel dir */
- string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 );
- break;
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH && ( root.flags || dir.flags ) )
- printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
- grid[ root.flags ][ dir.flags ], file->value );
-# endif
-
- /*
- * Now do the special :P modifier when no file was present.
- * (none) (none)
- * [dir1.dir2] [dir1]
- * [dir] [000000]
- * [.dir] (none)
- * [] []
- */
-
- if ( ( file->value[ file->size - 1 ] == ']' ) && f->parent )
- {
- char * p = file->value + file->size;
- while ( p-- > file->value )
- {
- if ( *p == '.' )
- {
- /* If we've truncated everything and left with '[',
- return empty string. */
- if ( p == file->value + 1 )
- string_truncate( file, 0 );
- else
- {
- string_truncate( file, p - file->value );
- string_push_back( file, ']' );
- }
- break;
- }
-
- if ( *p == '-' )
- {
- /* handle .- or - */
- if ( ( p > file->value ) && ( p[ -1 ] == '.' ) )
- --p;
-
- *p++ = ']';
- break;
- }
-
- if ( *p == '[' )
- {
- if ( p[ 1 ] == ']' )
- {
- /* CONSIDER: I don't see any use of this code. We immediately
- break, and 'p' is a local variable. */
- p += 2;
- }
- else
- {
- string_truncate( file, p - file->value );
- string_append( file, "[000000]" );
- }
- break;
- }
- }
- }
-
- /* Now copy the file pieces. */
- if ( f->f_base.len )
- {
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
- }
-
- /* If there is no suffix, we append a "." onto all generated names. This
- * keeps VMS from appending its own (wrong) idea of what the suffix should
- * be.
- */
- if ( f->f_suffix.len )
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
- else if ( binding && f->f_base.len )
- string_push_back( file, '.' );
-
- if ( f->f_member.len )
- {
- string_push_back( file, '(' );
- string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
- string_push_back( file, ')' );
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH )
- printf( "built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
- f->f_root.len, f->f_root.ptr,
- f->f_dir.len, f->f_dir.ptr,
- f->f_base.len, f->f_base.ptr,
- f->f_suffix.len, f->f_suffix.ptr,
- f->f_member.len, f->f_member.ptr,
- file->value );
-# endif
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-void path_parent( PATHNAME * f )
-{
- if ( f->f_base.len )
- {
- f->f_base.ptr =
- f->f_suffix.ptr =
- f->f_member.ptr = "";
-
- f->f_base.len =
- f->f_suffix.len =
- f->f_member.len = 0;
- }
- else
- {
- f->parent = 1;
- }
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/pwd.c b/tools/build/v2/engine/pwd.c
index 90c8eb175d..93d8126032 100644
--- a/tools/build/v2/engine/pwd.c
+++ b/tools/build/v2/engine/pwd.c
@@ -4,7 +4,7 @@
#include "jam.h"
#include "lists.h"
-#include "newstr.h"
+#include "object.h"
#include "pathsys.h"
#include "mem.h"
@@ -29,7 +29,7 @@
/* The current directory can't change in bjam, so optimize this to cache
** the result.
*/
-static char * pwd_result = NULL;
+static OBJECT * pwd_result = NULL;
LIST*
@@ -46,9 +46,11 @@ pwd(void)
if (result_buffer)
{
#ifdef NT
- pwd_result = short_path_to_long_path(result_buffer);
+ OBJECT * result = object_new(result_buffer);
+ pwd_result = short_path_to_long_path(result);
+ object_free( result );
#else
- pwd_result = newstr(result_buffer);
+ pwd_result = object_new(result_buffer);
#endif
}
buffer_size *= 2;
@@ -62,5 +64,13 @@ pwd(void)
return L0;
}
}
- return list_new(L0, pwd_result);
+ return list_new( object_copy( pwd_result ) );
+}
+
+void pwd_done( void )
+{
+ if( pwd_result )
+ {
+ object_free( pwd_result );
+ }
}
diff --git a/tools/build/v2/engine/pwd.h b/tools/build/v2/engine/pwd.h
index 37cb531e4f..e6ed268bb2 100644
--- a/tools/build/v2/engine/pwd.h
+++ b/tools/build/v2/engine/pwd.h
@@ -5,6 +5,7 @@
#ifndef PWD_H
#define PWD_H
-LIST* pwd(void);
+LIST * pwd( void );
+void pwd_done( void );
#endif
diff --git a/tools/build/v2/engine/regexp.c b/tools/build/v2/engine/regexp.c
index 30197a2feb..b51b85b09c 100644
--- a/tools/build/v2/engine/regexp.c
+++ b/tools/build/v2/engine/regexp.c
@@ -152,7 +152,7 @@
* Utility definitions.
*/
#ifndef CHARBITS
-#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#define UCHARAT(p) ((int)*(const unsigned char *)(p))
#else
#define UCHARAT(p) ((int)*(p)&CHARBITS)
#endif
@@ -213,7 +213,7 @@ STATIC int strcspn();
* of the structure of the compiled regexp.
*/
regexp *
-regcomp( char *exp )
+regcomp( const char *exp )
{
register regexp *r;
register char *scan;
@@ -770,15 +770,15 @@ regoptail(
/*
* Global work variables for regexec().
*/
-static char *reginput; /* String-input pointer. */
-static char *regbol; /* Beginning of input, for ^ check. */
-static char **regstartp; /* Pointer to startp array. */
-static char **regendp; /* Ditto for endp. */
+static const char *reginput; /* String-input pointer. */
+static const char *regbol; /* Beginning of input, for ^ check. */
+static const char **regstartp; /* Pointer to startp array. */
+static const char **regendp; /* Ditto for endp. */
/*
* Forwards.
*/
-STATIC int regtry( regexp *prog, char *string );
+STATIC int regtry( regexp *prog, const char *string );
STATIC int regmatch( char *prog );
STATIC int regrepeat( char *p );
@@ -794,7 +794,7 @@ STATIC char *regprop();
int
regexec(
register regexp *prog,
- register char *string )
+ register const char *string )
{
register char *s;
@@ -859,11 +859,11 @@ regexec(
static int /* 0 failure, 1 success */
regtry(
regexp *prog,
- char *string )
+ const char *string )
{
register int i;
- register char * * sp;
- register char * * ep;
+ register const char * * sp;
+ register const char * * ep;
reginput = string;
regstartp = prog->startp;
@@ -982,7 +982,7 @@ regmatch( char * prog )
case OPEN+8:
case OPEN+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - OPEN;
save = reginput;
@@ -1010,7 +1010,7 @@ regmatch( char * prog )
case CLOSE+8:
case CLOSE+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - CLOSE;
save = reginput;
@@ -1029,7 +1029,7 @@ regmatch( char * prog )
}
break;
case BRANCH: {
- register char *save;
+ register const char *save;
if (OP(next) != BRANCH) /* No choice. */
next = OPERAND(scan); /* Avoid recursion. */
@@ -1050,7 +1050,7 @@ regmatch( char * prog )
case PLUS: {
register char nextch;
register int no;
- register char *save;
+ register const char *save;
register int min;
/*
@@ -1102,7 +1102,7 @@ static int
regrepeat( char *p )
{
register int count = 0;
- register char *scan;
+ register const char *scan;
register char *opnd;
scan = reginput;
diff --git a/tools/build/v2/engine/regexp.h b/tools/build/v2/engine/regexp.h
index 9d4604f60a..fccfb7dff8 100644
--- a/tools/build/v2/engine/regexp.h
+++ b/tools/build/v2/engine/regexp.h
@@ -9,8 +9,8 @@
#define NSUBEXP 10
typedef struct regexp {
- char *startp[NSUBEXP];
- char *endp[NSUBEXP];
+ const char *startp[NSUBEXP];
+ const char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
@@ -18,9 +18,9 @@ typedef struct regexp {
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
-regexp *regcomp( char *exp );
-int regexec( regexp *prog, char *string );
-void regerror( char *s );
+regexp *regcomp( const char *exp );
+int regexec( regexp *prog, const char *string );
+void regerror( const char *s );
/*
* The first byte of the regexp internal "program" is actually this magic
diff --git a/tools/build/v2/engine/rules.c b/tools/build/v2/engine/rules.c
index a0be1d3400..b9ff6191f5 100644
--- a/tools/build/v2/engine/rules.c
+++ b/tools/build/v2/engine/rules.c
@@ -9,7 +9,7 @@
# include "parse.h"
# include "variable.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "modules.h"
# include "search.h"
@@ -45,19 +45,10 @@
*/
static void set_rule_actions( RULE *, rule_actions * );
-static void set_rule_body ( RULE *, argument_list *, PARSE * procedure );
+static void set_rule_body ( RULE *, FUNCTION * procedure );
static struct hash * targethash = 0;
-struct _located_target
-{
- char * file_name;
- TARGET * target;
-};
-typedef struct _located_target LOCATED_TARGET ;
-
-static struct hash * located_targets = 0;
-
/*
* target_include() - adds the 'included' TARGET to the list of targets included
@@ -83,25 +74,20 @@ void target_include( TARGET * including, TARGET * included )
* target_module.
*/
-static RULE * enter_rule( char * rulename, module_t * target_module )
+static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
{
- RULE rule;
- RULE * r = &rule;
+ int found;
+ RULE * r;
- r->name = rulename;
-
- if ( hashenter( demand_rules( target_module ), (HASHDATA * *)&r ) )
+ r = (RULE *)hash_insert( demand_rules(target_module), rulename, &found );
+ if ( !found )
{
- r->name = newstr( rulename ); /* never freed */
- r->procedure = (PARSE *)0;
+ r->name = object_copy( rulename );
+ r->procedure = 0;
r->module = 0;
r->actions = 0;
- r->arguments = 0;
r->exported = 0;
r->module = target_module;
-#ifdef HAVE_PYTHON
- r->python_function = 0;
-#endif
}
return r;
}
@@ -116,14 +102,14 @@ static RULE * enter_rule( char * rulename, module_t * target_module )
static RULE * define_rule
(
module_t * src_module,
- char * rulename,
+ OBJECT * rulename,
module_t * target_module
)
{
RULE * r = enter_rule( rulename, target_module );
if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
{
- set_rule_body( r, 0, 0 );
+ set_rule_body( r, 0 );
set_rule_actions( r, 0 );
r->module = src_module; /* r will be executed in the source module */
}
@@ -133,13 +119,11 @@ static RULE * define_rule
void rule_free( RULE * r )
{
- freestr( r->name );
- r->name = "";
- parse_free( r->procedure );
+ object_free( r->name );
+ r->name = 0;
+ if ( r->procedure )
+ function_free( r->procedure );
r->procedure = 0;
- if ( r->arguments )
- args_free( r->arguments );
- r->arguments = 0;
if ( r->actions )
actions_free( r->actions );
r->actions = 0;
@@ -150,25 +134,20 @@ void rule_free( RULE * r )
* bindtarget() - return pointer to TARGET, creating it if necessary.
*/
-TARGET * bindtarget( char const * target_name )
+TARGET * bindtarget( OBJECT * target_name )
{
- TARGET target;
- TARGET * t = &target;
+ int found;
+ TARGET * t;
if ( !targethash )
targethash = hashinit( sizeof( TARGET ), "targets" );
- /* Perforce added const everywhere. No time to merge that change. */
-#ifdef NT
- target_name = short_path_to_long_path( (char *)target_name );
-#endif
- t->name = (char *)target_name;
-
- if ( hashenter( targethash, (HASHDATA * *)&t ) )
+ t = (TARGET *)hash_insert( targethash, target_name, &found );
+ if ( !found )
{
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = newstr( (char *)target_name ); /* never freed */
- t->boundname = t->name; /* default for T_FLAG_NOTFILE */
+ t->name = object_copy( target_name );
+ t->boundname = object_copy( t->name ); /* default for T_FLAG_NOTFILE */
}
return t;
@@ -184,14 +163,15 @@ static void bind_explicitly_located_target( void * xtarget, void * data )
SETTINGS * s = t->settings;
for ( ; s ; s = s->next )
{
- if ( strcmp( s->symbol, "LOCATE" ) == 0 )
+ if ( strcmp( object_str( s->symbol ), "LOCATE" ) == 0 )
{
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
/* We are binding a target with explicit LOCATE. So third
* argument is of no use: nothing will be returned through it.
*/
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
break;
}
}
@@ -206,81 +186,6 @@ void bind_explicitly_located_targets()
}
-/* TODO: It is probably not a good idea to use functions in other modules like
- this. */
-void call_bind_rule( char * target, char * boundname );
-
-
-TARGET * search_for_target ( char * name, LIST * search_path )
-{
- PATHNAME f[1];
- string buf[1];
- LOCATED_TARGET lt;
- LOCATED_TARGET * lta = &lt;
- time_t time;
- int found = 0;
- TARGET * result;
-
- string_new( buf );
-
- path_parse( name, f );
-
- f->f_grist.ptr = 0;
- f->f_grist.len = 0;
-
- while ( search_path )
- {
- f->f_root.ptr = search_path->string;
- f->f_root.len = strlen( search_path->string );
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- lt.file_name = buf->value ;
-
- if ( !located_targets )
- located_targets = hashinit( sizeof(LOCATED_TARGET),
- "located targets" );
-
- if ( hashcheck( located_targets, (HASHDATA * *)&lta ) )
- {
- return lta->target;
- }
-
- timestamp( buf->value, &time );
- if ( time )
- {
- found = 1;
- break;
- }
-
- search_path = list_next( search_path );
- }
-
- if ( !found )
- {
- f->f_root.ptr = 0;
- f->f_root.len = 0;
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- timestamp( buf->value, &time );
- }
-
- result = bindtarget( name );
- result->boundname = newstr( buf->value );
- result->time = time;
- result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
-
- call_bind_rule( result->name, result->boundname );
-
- string_free( buf );
-
- return result;
-}
-
-
/*
* copytarget() - make a new target with the old target's name.
*
@@ -291,8 +196,8 @@ TARGET * copytarget( const TARGET * ot )
{
TARGET * t = (TARGET *)BJAM_MALLOC( sizeof( *t ) );
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = copystr( ot->name );
- t->boundname = t->name;
+ t->name = object_copy( ot->name );
+ t->boundname = object_copy( t->name );
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
@@ -304,7 +209,7 @@ TARGET * copytarget( const TARGET * ot )
* touch_target() - mark a target to simulate being new.
*/
-void touch_target( char * t )
+void touch_target( OBJECT * t )
{
bindtarget( t )->flags |= T_FLAG_TOUCHED;
}
@@ -320,8 +225,9 @@ void touch_target( char * t )
TARGETS * targetlist( TARGETS * chain, LIST * target_names )
{
- for ( ; target_names; target_names = list_next( target_names ) )
- chain = targetentry( chain, bindtarget( target_names->string ) );
+ LISTITER iter = list_begin( target_names ), end = list_end( target_names );
+ for ( ; iter != end; iter = list_next( iter ) )
+ chain = targetentry( chain, bindtarget( list_item( iter ) ) );
return chain;
}
@@ -368,6 +274,21 @@ TARGETS * targetchain( TARGETS * chain, TARGETS * targets )
}
/*
+ * action_free - decrement the ACTIONs refrence count
+ * and (maybe) free it.
+ */
+
+void action_free ( ACTION * action )
+{
+ if ( --action->refs == 0 )
+ {
+ freetargets( action->targets );
+ freetargets( action->sources );
+ BJAM_FREE( action );
+ }
+}
+
+/*
* actionlist() - append to an ACTION chain.
*/
@@ -377,6 +298,7 @@ ACTIONS * actionlist( ACTIONS * chain, ACTION * action )
actions->action = action;
+ ++action->refs;
if ( !chain ) chain = actions;
else chain->tail->next = actions;
chain->tail = actions;
@@ -397,13 +319,13 @@ static SETTINGS * settings_freelist;
* the head of the settings chain.
*/
-SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
+SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value )
{
SETTINGS * v;
/* Look for previous settings. */
for ( v = head; v; v = v->next )
- if ( !strcmp( v->symbol, symbol ) )
+ if ( object_equal( v->symbol, symbol ) )
break;
/* If not previously set, alloc a new. */
@@ -418,10 +340,9 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
else
v = (SETTINGS *)BJAM_MALLOC( sizeof( *v ) );
- v->symbol = newstr( symbol );
+ v->symbol = object_copy( symbol );
v->value = value;
v->next = head;
- v->multiple = 0;
head = v;
}
else if ( flag == VAR_APPEND )
@@ -445,10 +366,10 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
* pushsettings() - set all target specific variables.
*/
-void pushsettings( SETTINGS * v )
+void pushsettings( struct module_t * module, SETTINGS * v )
{
for ( ; v; v = v->next )
- v->value = var_swap( v->symbol, v->value );
+ v->value = var_swap( module, v->symbol, v->value );
}
@@ -456,9 +377,9 @@ void pushsettings( SETTINGS * v )
* popsettings() - reset target specific variables to their pre-push values.
*/
-void popsettings( SETTINGS * v )
+void popsettings( struct module_t * module, SETTINGS * v )
{
- pushsettings( v ); /* just swap again */
+ pushsettings( module, v ); /* just swap again */
}
@@ -471,7 +392,7 @@ SETTINGS * copysettings( SETTINGS * head )
SETTINGS * copy = 0;
SETTINGS * v;
for ( v = head; v; v = v->next )
- copy = addsettings( copy, VAR_SET, v->symbol, list_copy( 0, v->value ) );
+ copy = addsettings( copy, VAR_SET, v->symbol, list_copy( v->value ) );
return copy;
}
@@ -500,6 +421,7 @@ void freeactions( ACTIONS * chain )
while ( chain )
{
ACTIONS * n = chain->next;
+ action_free( chain->action );
BJAM_FREE( chain );
chain = n;
}
@@ -515,7 +437,7 @@ void freesettings( SETTINGS * v )
while ( v )
{
SETTINGS * n = v->next;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v->value );
v->next = settings_freelist;
settings_freelist = v;
@@ -527,10 +449,19 @@ void freesettings( SETTINGS * v )
static void freetarget( void * xt, void * data )
{
TARGET * t = (TARGET *)xt;
- if ( t->settings ) freesettings( t->settings );
- if ( t->depends ) freetargets ( t->depends );
- if ( t->includes ) freetarget ( t->includes, (void *)0 );
- if ( t->actions ) freeactions ( t->actions );
+ if ( t->name ) object_free ( t->name );
+ if ( t->boundname ) object_free ( t->boundname );
+ if ( t->settings ) freesettings( t->settings );
+ if ( t->depends ) freetargets ( t->depends );
+ if ( t->dependants ) freetargets ( t->dependants );
+ if ( t->parents ) freetargets ( t->parents );
+ if ( t->actions ) freeactions ( t->actions );
+
+ if ( t->includes )
+ {
+ freetarget( t->includes, (void *)0 );
+ BJAM_FREE( t->includes );
+ }
}
@@ -540,8 +471,11 @@ static void freetarget( void * xt, void * data )
void rules_done()
{
- hashenumerate( targethash, freetarget, 0 );
- hashdone( targethash );
+ if ( targethash )
+ {
+ hashenumerate( targethash, freetarget, 0 );
+ hashdone( targethash );
+ }
while ( settings_freelist )
{
SETTINGS * n = settings_freelist->next;
@@ -552,43 +486,6 @@ void rules_done()
/*
- * args_new() - make a new reference-counted argument list.
- */
-
-argument_list * args_new()
-{
- argument_list * r = (argument_list *)BJAM_MALLOC( sizeof(argument_list) );
- r->reference_count = 0;
- lol_init( r->data );
- return r;
-}
-
-
-/*
- * args_refer() - add a new reference to the given argument list.
- */
-
-void args_refer( argument_list * a )
-{
- ++a->reference_count;
-}
-
-
-/*
- * args_free() - release a reference to the given argument list.
- */
-
-void args_free( argument_list * a )
-{
- if ( --a->reference_count <= 0 )
- {
- lol_free( a->data );
- BJAM_FREE( a );
- }
-}
-
-
-/*
* actions_refer() - add a new reference to the given actions.
*/
@@ -606,29 +503,22 @@ void actions_free( rule_actions * a )
{
if ( --a->reference_count <= 0 )
{
- freestr( a->command );
+ function_free( a->command );
list_free( a->bindlist );
BJAM_FREE( a );
}
}
-
/*
* set_rule_body() - set the argument list and procedure of the given rule.
*/
-static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure )
+static void set_rule_body( RULE * rule, FUNCTION * procedure )
{
- if ( args )
- args_refer( args );
- if ( rule->arguments )
- args_free( rule->arguments );
- rule->arguments = args;
-
if ( procedure )
- parse_refer( procedure );
+ function_refer( procedure );
if ( rule->procedure )
- parse_free( rule->procedure );
+ function_free( rule->procedure );
rule->procedure = procedure;
}
@@ -638,16 +528,20 @@ static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure
* global module.
*/
-static char * global_rule_name( RULE * r )
+static OBJECT * global_rule_name( RULE * r )
{
if ( r->module == root_module() )
- return r->name;
+ return object_copy( r->name );
{
char name[4096] = "";
- strncat( name, r->module->name, sizeof( name ) - 1 );
- strncat( name, r->name, sizeof( name ) - 1 );
- return newstr( name);
+ if ( r->module->name )
+ {
+ strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
+ strncat( name, ".", sizeof( name ) - 1 );
+ }
+ strncat( name, object_str( r->name ), sizeof( name ) - 1 );
+ return object_new( name );
}
}
@@ -663,9 +557,9 @@ static RULE * global_rule( RULE * r )
return r;
{
- char * name = global_rule_name( r );
+ OBJECT * name = global_rule_name( r );
RULE * result = define_rule( r->module, name, root_module() );
- freestr( name );
+ object_free( name );
return result;
}
}
@@ -677,19 +571,19 @@ static RULE * global_rule( RULE * r )
* exported to the global module as modulename.rulename.
*/
-RULE * new_rule_body( module_t * m, char * rulename, argument_list * args, PARSE * procedure, int exported )
+RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure, int exported )
{
RULE * local = define_rule( m, rulename, m );
local->exported = exported;
- set_rule_body( local, args, procedure );
+ set_rule_body( local, procedure );
/* Mark the procedure with the global rule name, regardless of whether the
* rule is exported. That gives us something reasonably identifiable that we
* can use, e.g. in profiling output. Only do this once, since this could be
* called multiple times with the same procedure.
*/
- if ( procedure->rulename == 0 )
- procedure->rulename = global_rule_name( local );
+ if ( function_rulename( procedure ) == 0 )
+ function_set_rulename( procedure, global_rule_name( local ) );
return local;
}
@@ -705,10 +599,11 @@ static void set_rule_actions( RULE * rule, rule_actions * actions )
}
-static rule_actions * actions_new( char * command, LIST * bindlist, int flags )
+static rule_actions * actions_new( FUNCTION * command, LIST * bindlist, int flags )
{
rule_actions * result = (rule_actions *)BJAM_MALLOC( sizeof( rule_actions ) );
- result->command = copystr( command );
+ function_refer( command );
+ result->command = command;
result->bindlist = bindlist;
result->flags = flags;
result->reference_count = 0;
@@ -716,7 +611,7 @@ static rule_actions * actions_new( char * command, LIST * bindlist, int flags )
}
-RULE * new_rule_actions( module_t * m, char * rulename, char * command, LIST * bindlist, int flags )
+RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags )
{
RULE * local = define_rule( m, rulename, m );
RULE * global = global_rule( local );
@@ -733,32 +628,37 @@ RULE * new_rule_actions( module_t * m, char * rulename, char * command, LIST * b
* modules, look in module 'name1' for rule 'name2'.
*/
-RULE * lookup_rule( char * rulename, module_t * m, int local_only )
+RULE * lookup_rule( OBJECT * rulename, module_t * m, int local_only )
{
- RULE rule;
- RULE * r = &rule;
+ RULE * r;
RULE * result = 0;
module_t * original_module = m;
- r->name = rulename;
-
if ( m->class_module )
m = m->class_module;
- if ( m->rules && hashcheck( m->rules, (HASHDATA * *)&r ) )
+ if ( m->rules && ( r = (RULE *)hash_find( m->rules, rulename ) ) )
result = r;
else if ( !local_only && m->imported_modules )
{
/* Try splitting the name into module and rule. */
- char *p = strchr( r->name, '.' ) ;
+ char *p = strchr( object_str( rulename ), '.' ) ;
if ( p )
{
- *p = '\0';
+ string buf[1];
+ OBJECT * module_part;
+ OBJECT * rule_part;
+ string_new( buf );
+ string_append_range( buf, object_str( rulename ), p );
+ module_part = object_new( buf->value );
+ rule_part = object_new( p + 1 );
/* Now, r->name keeps the module name, and p+1 keeps the rule name.
*/
- if ( hashcheck( m->imported_modules, (HASHDATA * *)&r ) )
- result = lookup_rule( p + 1, bindmodule( rulename ), 1 );
- *p = '.';
+ if ( hash_find( m->imported_modules, module_part ) )
+ result = lookup_rule( rule_part, bindmodule( module_part ), 1 );
+ object_free( rule_part );
+ object_free( module_part );
+ string_free( buf );
}
}
@@ -786,7 +686,7 @@ RULE * lookup_rule( char * rulename, module_t * m, int local_only )
}
-RULE * bindrule( char * rulename, module_t * m )
+RULE * bindrule( OBJECT * rulename, module_t * m )
{
RULE * result = lookup_rule( rulename, m, 0 );
if ( !result )
@@ -801,10 +701,24 @@ RULE * bindrule( char * rulename, module_t * m )
}
-RULE * import_rule( RULE * source, module_t * m, char * name )
+RULE * import_rule( RULE * source, module_t * m, OBJECT * name )
{
RULE * dest = define_rule( source->module, name, m );
- set_rule_body( dest, source->arguments, source->procedure );
+ set_rule_body( dest, source->procedure );
set_rule_actions( dest, source->actions );
return dest;
}
+
+
+void rule_localize( RULE * rule, module_t * m )
+{
+ rule->module = m;
+ if ( rule->procedure )
+ {
+ FUNCTION * procedure = function_unbind_variables( rule->procedure );
+ function_refer( procedure );
+ function_free( rule->procedure );
+ rule->procedure = procedure;
+ }
+}
+
diff --git a/tools/build/v2/engine/rules.h b/tools/build/v2/engine/rules.h
index 806a1469c0..823fbd1f55 100644
--- a/tools/build/v2/engine/rules.h
+++ b/tools/build/v2/engine/rules.h
@@ -15,7 +15,7 @@
#include "modules.h"
#include "jam.h"
-#include "parse.h"
+#include "function.h"
/*
@@ -52,20 +52,13 @@ typedef struct _settings SETTINGS ;
/* RULE - a generic jam rule, the product of RULE and ACTIONS. */
-/* A rule's argument list. */
-struct argument_list
-{
- int reference_count;
- LOL data[1];
-};
-
/* Build actions corresponding to a rule. */
struct rule_actions
{
- int reference_count;
- char * command; /* command string from ACTIONS */
- LIST * bindlist;
- int flags; /* modifiers on ACTIONS */
+ int reference_count;
+ FUNCTION * command; /* command string from ACTIONS */
+ LIST * bindlist;
+ int flags; /* modifiers on ACTIONS */
#define RULE_NEWSRCS 0x01 /* $(>) is updated sources only */
#define RULE_TOGETHER 0x02 /* combine actions on single target */
@@ -80,19 +73,14 @@ typedef struct argument_list argument_list;
struct _rule
{
- char * name;
- PARSE * procedure; /* parse tree from RULE */
- argument_list * arguments; /* argument checking info, or NULL for unchecked
- */
+ OBJECT * name;
+ FUNCTION * procedure;
rule_actions * actions; /* build actions, or NULL for no actions */
module_t * module; /* module in which this rule is executed */
int exported; /* nonzero if this rule is supposed to appear in
* the global module and be automatically
* imported into other modules
*/
-#ifdef HAVE_PYTHON
- PyObject * python_function;
-#endif
};
/* ACTIONS - a chain of ACTIONs. */
@@ -110,16 +98,19 @@ struct _action
TARGETS * targets;
TARGETS * sources; /* aka $(>) */
char running; /* has been started */
+#define A_INIT 0
+#define A_RUNNING_NOEXEC 1
+#define A_RUNNING 2
char status; /* see TARGET status */
+ int refs;
};
/* SETTINGS - variables to set when executing a TARGET's ACTIONS. */
struct _settings
{
SETTINGS * next;
- char * symbol; /* symbol name for var_set() */
+ OBJECT * symbol; /* symbol name for var_set() */
LIST * value; /* symbol value for var_set() */
- int multiple;
};
/* TARGETS - a chain of TARGETs. */
@@ -133,8 +124,8 @@ struct _targets
/* TARGET - an entity (e.g. a file) that can be built. */
struct _target
{
- char * name;
- char * boundname; /* if search() relocates target */
+ OBJECT * name;
+ OBJECT * boundname; /* if search() relocates target */
ACTIONS * actions; /* rules to execute, if any */
SETTINGS * settings; /* variables to define */
@@ -220,6 +211,7 @@ struct _target
#define T_MAKE_ACTIVE 2 /* make1(target) in make1b() */
#define T_MAKE_RUNNING 3 /* make1(target) running commands */
#define T_MAKE_DONE 4 /* make1(target) done */
+#define T_MAKE_NOEXEC_DONE 5 /* make1(target) done with -n in effect */
#ifdef OPT_SEMAPHORE
#define T_MAKE_SEMAPHORE 5 /* Special target type for semaphores */
@@ -235,44 +227,41 @@ struct _target
TARGETS * parents; /* used by make1() for completion */
char * cmds; /* type-punned command list */
- char * failed;
+ const char * failed;
};
/* Action related functions. */
+void action_free ( ACTION * );
ACTIONS * actionlist ( ACTIONS *, ACTION * );
void freeactions ( ACTIONS * );
-SETTINGS * addsettings ( SETTINGS *, int flag, char * symbol, LIST * value );
-void pushsettings ( SETTINGS * );
-void popsettings ( SETTINGS * );
+SETTINGS * addsettings ( SETTINGS *, int flag, OBJECT * symbol, LIST * value );
+void pushsettings ( struct module_t * module, SETTINGS * );
+void popsettings ( struct module_t * module, SETTINGS * );
SETTINGS * copysettings ( SETTINGS * );
void freesettings ( SETTINGS * );
void actions_refer( rule_actions * );
void actions_free ( rule_actions * );
-/* Argument list related functions. */
-void args_free ( argument_list * );
-argument_list * args_new ();
-void args_refer( argument_list * );
-
/* Rule related functions. */
-RULE * bindrule ( char * rulename, module_t * );
-RULE * import_rule ( RULE * source, module_t *, char * name );
-RULE * new_rule_body ( module_t *, char * rulename, argument_list *, PARSE * procedure, int exprt );
-RULE * new_rule_actions( module_t *, char * rulename, char * command, LIST * bindlist, int flags );
+RULE * bindrule ( OBJECT * rulename, module_t * );
+RULE * import_rule ( RULE * source, module_t *, OBJECT * name );
+void rule_localize ( RULE * rule, module_t * module );
+RULE * new_rule_body ( module_t *, OBJECT * rulename, FUNCTION * func, int exprt );
+RULE * new_rule_actions( module_t *, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags );
void rule_free ( RULE * );
/* Target related functions. */
void bind_explicitly_located_targets();
-TARGET * bindtarget ( char const * target_name );
+TARGET * bindtarget ( OBJECT * target_name );
TARGET * copytarget ( TARGET const * t );
void freetargets ( TARGETS * );
-TARGET * search_for_target ( char * name, LIST * search_path );
TARGETS * targetchain ( TARGETS * chain, TARGETS * );
TARGETS * targetentry ( TARGETS * chain, TARGET * );
void target_include ( TARGET * including, TARGET * included );
TARGETS * targetlist ( TARGETS * chain, LIST * target_names );
-void touch_target ( char * t );
+void touch_target ( OBJECT * t );
+void clear_includes ( TARGET * );
/* Final module cleanup. */
void rules_done();
diff --git a/tools/build/v2/engine/scan.c b/tools/build/v2/engine/scan.c
index 11c44c0e21..915ec21f44 100644
--- a/tools/build/v2/engine/scan.c
+++ b/tools/build/v2/engine/scan.c
@@ -10,7 +10,8 @@
#include "scan.h"
#include "jamgram.h"
#include "jambase.h"
-#include "newstr.h"
+#include "object.h"
+#include "constants.h"
/*
* scan.c - the jam yacc scanner
@@ -41,7 +42,7 @@ struct include
char * string; /* pointer into current line */
char * * strings; /* for yyfparse() -- text to parse */
FILE * file; /* for yyfparse() -- file being read */
- char * fname; /* for yyfparse() -- file name */
+ OBJECT * fname; /* for yyfparse() -- file name */
int line; /* line counter for error messages */
char buf[ 512 ]; /* for yyfparse() -- line buffer */
};
@@ -67,7 +68,7 @@ void yymode( int n )
}
-void yyerror( char * s )
+void yyerror( const char * s )
{
/* We use yylval instead of incp to access the error location information as
* the incp pointer will already be reset to 0 in case the error occurred at
@@ -82,7 +83,7 @@ void yyerror( char * s )
* TODO: Test the theory about when yylval and incp location information are
* the same and when they differ.
*/
- printf( "%s:%d: %s at %s\n", yylval.file, yylval.line, s, symdump( &yylval ) );
+ printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s, symdump( &yylval ) );
++anyerrors;
}
@@ -93,7 +94,7 @@ int yyanyerrors()
}
-void yyfparse( char * s )
+void yyfparse( OBJECT * s )
{
struct include * i = (struct include *)BJAM_MALLOC( sizeof( *i ) );
@@ -101,13 +102,13 @@ void yyfparse( char * s )
i->string = "";
i->strings = 0;
i->file = 0;
- i->fname = copystr( s );
+ i->fname = object_copy( s );
i->line = 0;
i->next = incp;
incp = i;
/* If the filename is "+", it means use the internal jambase. */
- if ( !strcmp( s, "+" ) )
+ if ( !strcmp( object_str( s ), "+" ) )
i->strings = jambase;
}
@@ -151,8 +152,8 @@ int yyline()
if ( !i->file )
{
FILE * f = stdin;
- if ( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
- perror( i->fname );
+ if ( strcmp( object_str( i->fname ), "-" ) && !( f = fopen( object_str( i->fname ), "r" ) ) )
+ perror( object_str( i->fname ) );
i->file = f;
}
@@ -174,7 +175,7 @@ int yyline()
/* Close file, free name. */
if ( i->file && ( i->file != stdin ) )
fclose( i->file );
- freestr( i->fname );
+ object_free( i->fname );
BJAM_FREE( (char *)i );
return EOF;
@@ -252,7 +253,7 @@ int yylex()
*b = 0;
yylval.type = STRING;
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
yylval.file = incp->fname;
yylval.line = incp->line;
}
@@ -361,12 +362,12 @@ int yylex()
if ( ( *buf == *k->word ) && !strcmp( k->word, buf ) )
{
yylval.type = k->type;
- yylval.string = k->word; /* used by symdump */
+ yylval.keyword = k->word; /* used by symdump */
break;
}
if ( yylval.type == ARG )
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
}
if ( DEBUG_SCAN )
@@ -388,11 +389,11 @@ static char * symdump( YYSTYPE * s )
static char buf[ BIGGEST_TOKEN + 20 ];
switch ( s->type )
{
- case EOF : sprintf( buf, "EOF" ); break;
- case 0 : sprintf( buf, "unknown symbol %s", s->string ); break;
- case ARG : sprintf( buf, "argument %s" , s->string ); break;
- case STRING: sprintf( buf, "string \"%s\"" , s->string ); break;
- default : sprintf( buf, "keyword %s" , s->string ); break;
+ case EOF : sprintf( buf, "EOF" ); break;
+ case 0 : sprintf( buf, "unknown symbol %s", object_str( s->string ) ); break;
+ case ARG : sprintf( buf, "argument %s" , object_str( s->string ) ); break;
+ case STRING: sprintf( buf, "string \"%s\"" , object_str( s->string ) ); break;
+ default : sprintf( buf, "keyword %s" , s->keyword ); break;
}
return buf;
}
@@ -403,7 +404,7 @@ static char * symdump( YYSTYPE * s )
* transitions that produce a parse.
*/
-void yyinput_stream( char * * name, int * line )
+void yyinput_stream( OBJECT * * name, int * line )
{
if ( incp )
{
@@ -412,7 +413,7 @@ void yyinput_stream( char * * name, int * line )
}
else
{
- *name = "(builtin)";
+ *name = constant_builtin;
*line = -1;
}
}
diff --git a/tools/build/v2/engine/scan.h b/tools/build/v2/engine/scan.h
index 3fad1c24cf..b672d00262 100644
--- a/tools/build/v2/engine/scan.h
+++ b/tools/build/v2/engine/scan.h
@@ -31,25 +31,26 @@
typedef struct _YYSTYPE
{
- int type;
- char * string;
- PARSE * parse;
- LIST * list;
- int number;
- char * file;
- int line;
+ int type;
+ OBJECT * string;
+ PARSE * parse;
+ LIST * list;
+ int number;
+ OBJECT * file;
+ int line;
+ const char * keyword;
} YYSTYPE;
extern YYSTYPE yylval;
void yymode( int n );
-void yyerror( char * s );
+void yyerror( const char * s );
int yyanyerrors();
-void yyfparse( char * s );
+void yyfparse( OBJECT * s );
int yyline();
int yylex();
int yyparse();
-void yyinput_stream( char * * name, int * line );
+void yyinput_stream( OBJECT * * name, int * line );
# define SCAN_NORMAL 0 /* normal parsing */
# define SCAN_STRING 1 /* look only for matching } */
diff --git a/tools/build/v2/engine/search.c b/tools/build/v2/engine/search.c
index 6c23d97a14..e3d287a679 100644
--- a/tools/build/v2/engine/search.c
+++ b/tools/build/v2/engine/search.c
@@ -16,7 +16,7 @@
#include "timestamp.h"
#include "pathsys.h"
#include "variable.h"
-#include "newstr.h"
+#include "object.h"
#include "compile.h"
#include "strings.h"
#include "hash.h"
@@ -26,8 +26,8 @@
typedef struct _binding
{
- char * binding;
- char * target;
+ OBJECT * binding;
+ OBJECT * target;
} BINDING;
static struct hash *explicit_bindings = 0;
@@ -35,22 +35,15 @@ static struct hash *explicit_bindings = 0;
void call_bind_rule
(
- char * target_,
- char * boundname_
+ OBJECT * target_,
+ OBJECT * boundname_
)
{
- LIST * bind_rule = var_get( "BINDRULE" );
- if ( bind_rule )
+ LIST * bind_rule = var_get( root_module(), constant_BINDRULE );
+ if ( !list_empty( bind_rule ) )
{
- /* No guarantee that the target is an allocated string, so be on the
- * safe side.
- */
- char * target = copystr( target_ );
-
- /* Likewise, do not rely on implementation details of newstr.c: allocate
- * a copy of boundname.
- */
- char * boundname = copystr( boundname_ );
+ OBJECT * target = object_copy( target_ );
+ OBJECT * boundname = object_copy( boundname_ );
if ( boundname && target )
{
/* Prepare the argument list. */
@@ -58,11 +51,11 @@ void call_bind_rule
frame_init( frame );
/* First argument is the target name. */
- lol_add( frame->args, list_new( L0, target ) );
+ lol_add( frame->args, list_new( target ) );
- lol_add( frame->args, list_new( L0, boundname ) );
+ lol_add( frame->args, list_new( boundname ) );
if ( lol_get( frame->args, 1 ) )
- evaluate_rule( bind_rule->string, frame );
+ list_free( evaluate_rule( list_front( bind_rule ), frame ) );
/* Clean up */
frame_free( frame );
@@ -70,9 +63,9 @@ void call_bind_rule
else
{
if ( boundname )
- freestr( boundname );
+ object_free( boundname );
if ( target )
- freestr( target );
+ object_free( target );
}
}
}
@@ -93,21 +86,21 @@ void call_bind_rule
* the third argument.
*/
-char *
+OBJECT *
search(
- char *target,
+ OBJECT * target,
time_t *time,
- char **another_target,
+ OBJECT * * another_target,
int file
)
{
PATHNAME f[1];
- LIST *varlist;
- string buf[1];
- int found = 0;
+ LIST * varlist;
+ string buf[1];
+ int found = 0;
/* Will be set to 1 if target location is specified via LOCATE. */
- int explicitly_located = 0;
- char *boundname = 0;
+ int explicitly_located = 0;
+ OBJECT * boundname = 0;
if ( another_target )
*another_target = 0;
@@ -119,55 +112,64 @@ search(
string_new( buf );
/* Parse the filename */
- path_parse( target, f );
+ path_parse( object_str( target ), f );
f->f_grist.ptr = 0;
f->f_grist.len = 0;
- if ( ( varlist = var_get( "LOCATE" ) ) )
- {
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ varlist = var_get( root_module(), constant_LOCATE );
+ if ( !list_empty( varlist ) )
+ {
+ OBJECT * key;
+ f->f_root.ptr = object_str( list_front( varlist ) );
+ f->f_root.len = strlen( object_str( list_front( varlist ) ) );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "locate %s: %s\n", target, buf->value );
+ printf( "locate %s: %s\n", object_str( target ), buf->value );
explicitly_located = 1;
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
found = 1;
}
- else if ( ( varlist = var_get( "SEARCH" ) ) )
+ else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
{
- while ( varlist )
+ LISTITER iter = list_begin( varlist ), end = list_end( varlist );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- BINDING b, *ba = &b;
+ BINDING * ba;
file_info_t *ff;
+ OBJECT * key;
+ OBJECT * test_path;
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ f->f_root.ptr = object_str( list_item( iter ) );
+ f->f_root.len = strlen( object_str( list_item( iter ) ) );
string_truncate( buf, 0 );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
-
- ff = file_query(buf->value);
- timestamp( buf->value, time );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- b.binding = buf->value;
+ test_path = object_new( buf->value );
+ key = path_as_key( test_path );
+ object_free( test_path );
+ ff = file_query( key );
+ timestamp( key, time );
- if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
+ if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
{
if ( DEBUG_SEARCH )
printf(" search %s: found explicitly located target %s\n",
- target, ba->target);
+ object_str( target ), object_str( ba->target ) );
if ( another_target )
*another_target = ba->target;
found = 1;
+ object_free( key );
break;
}
else if ( ff && ff->time )
@@ -175,11 +177,11 @@ search(
if ( !file || ff->is_file )
{
found = 1;
+ object_free( key );
break;
}
}
-
- varlist = list_next( varlist );
+ object_free( key );
}
}
@@ -188,6 +190,7 @@ search(
/* Look for the obvious */
/* This is a questionable move. Should we look in the */
/* obvious place if SEARCH is set? */
+ OBJECT * key;
f->f_root.ptr = 0;
f->f_root.len = 0;
@@ -196,24 +199,34 @@ search(
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
}
- boundname = newstr( buf->value );
+ boundname = object_new( buf->value );
string_free( buf );
if ( explicitly_located )
{
- BINDING b;
- BINDING * ba = &b;
- b.binding = boundname;
- b.target = target;
+ int found;
+ BINDING * ba;
+ OBJECT * key = path_as_key( boundname );
/* CONSIDER: we probably should issue a warning is another file
is explicitly bound to the same location. This might break
compatibility, though. */
- hashenter( explicit_bindings, (HASHDATA * *)&ba );
+ ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
+ if ( !found )
+ {
+ ba->binding = key;
+ ba->target = target;
+ }
+ else
+ {
+ object_free( key );
+ }
}
/* prepare a call to BINDRULE if the variable is set */
@@ -221,3 +234,19 @@ search(
return boundname;
}
+
+
+static void free_binding( void * xbinding, void * data )
+{
+ BINDING * binding = (BINDING *)xbinding;
+ object_free( binding->binding );
+}
+
+void search_done( void )
+{
+ if ( explicit_bindings )
+ {
+ hashenumerate( explicit_bindings, free_binding, (void *)0 );
+ hashdone( explicit_bindings );
+ }
+}
diff --git a/tools/build/v2/engine/search.h b/tools/build/v2/engine/search.h
index c364cac03b..0b6583996b 100644
--- a/tools/build/v2/engine/search.h
+++ b/tools/build/v2/engine/search.h
@@ -8,4 +8,13 @@
* search.h - find a target along $(SEARCH) or $(LOCATE)
*/
-char *search( char *target, time_t *time, char **another_target, int file );
+#ifndef SEARCH_SW20111118_H
+#define SEARCH_SW20111118_H
+
+#include "object.h"
+#include <time.h>
+
+OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target, int file );
+void search_done( void );
+
+#endif
diff --git a/tools/build/v2/engine/subst.c b/tools/build/v2/engine/subst.c
index 75524ecc12..156670f1e9 100644
--- a/tools/build/v2/engine/subst.c
+++ b/tools/build/v2/engine/subst.c
@@ -3,62 +3,64 @@
#include "regexp.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
-#include "parse.h"
#include "compile.h"
#include "frames.h"
+#include "builtins.h"
struct regex_entry
{
- const char* pattern;
+ OBJECT* pattern;
regexp* regex;
};
typedef struct regex_entry regex_entry;
static struct hash* regex_hash;
-regexp* regex_compile( const char* pattern )
+regexp* regex_compile( OBJECT* pattern )
{
- regex_entry entry, *e = &entry;
- entry.pattern = pattern;
+ int found;
+ regex_entry * e ;
if ( !regex_hash )
regex_hash = hashinit(sizeof(regex_entry), "regex");
- if ( hashenter( regex_hash, (HASHDATA **)&e ) )
+ e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
+ if ( !found )
+ {
+ e->pattern = object_copy( pattern );
e->regex = regcomp( (char*)pattern );
+ }
return e->regex;
}
-LIST*
-builtin_subst(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_subst( FRAME * frame, int flags )
{
LIST* result = L0;
LIST* arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
- if ( arg1 && list_next(arg1) && list_next(list_next(arg1)) )
+ if ( iter != end && list_next( iter ) != end && list_next( list_next( iter ) ) != end )
{
- const char* source = arg1->string;
- const char* pattern = list_next(arg1)->string;
+ const char* source = object_str( list_item( iter ) );
+ OBJECT * pattern = list_item( list_next( iter ) );
regexp* repat = regex_compile( pattern );
if ( regexec( repat, (char*)source) )
{
- LIST* subst = list_next(arg1);
+ LISTITER subst = list_next( iter );
- while ((subst = list_next(subst)) != L0)
+ while ( ( subst = list_next( subst ) ) != end )
{
# define BUFLEN 4096
char buf[BUFLEN + 1];
- const char* in = subst->string;
+ const char* in = object_str( list_item( subst ) );
char* out = buf;
- for ( in = subst->string; *in && out < buf + BUFLEN; ++in )
+ for ( ; *in && out < buf + BUFLEN; ++in )
{
if ( *in == '\\' || *in == '$' )
{
@@ -83,7 +85,7 @@ builtin_subst(
}
*out = 0;
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( buf ) );
#undef BUFLEN
}
}
@@ -92,3 +94,20 @@ builtin_subst(
return result;
}
+
+static void free_regex( void * xregex, void * data )
+{
+ regex_entry * regex = (regex_entry *)xregex;
+ object_free( regex->pattern );
+ BJAM_FREE( regex->regex );
+}
+
+
+void regex_done()
+{
+ if ( regex_hash )
+ {
+ hashenumerate( regex_hash, free_regex, (void *)0 );
+ hashdone( regex_hash );
+ }
+}
diff --git a/tools/build/v2/engine/timestamp.c b/tools/build/v2/engine/timestamp.c
index 8a59c8c0e0..6e4ed7326a 100644
--- a/tools/build/v2/engine/timestamp.c
+++ b/tools/build/v2/engine/timestamp.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "timestamp.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -32,12 +32,12 @@
typedef struct _binding BINDING;
struct _binding {
- char *name;
- short flags;
+ OBJECT * name;
+ short flags;
# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
- short progress;
+ short progress;
# define BIND_INIT 0 /* never seen */
# define BIND_NOENTRY 1 /* timestamp requested but file never found */
@@ -45,11 +45,11 @@ struct _binding {
# define BIND_MISSING 3 /* file found but can't get timestamp */
# define BIND_FOUND 4 /* file found and time stamped */
- time_t time; /* update time - 0 if not exist */
+ time_t time; /* update time - 0 if not exist */
};
static struct hash * bindhash = 0;
-static void time_enter( void *, char *, int, time_t );
+static void time_enter( void *, OBJECT *, int, time_t );
static char * time_progress[] =
{
@@ -65,49 +65,32 @@ static char * time_progress[] =
* timestamp() - return timestamp on a file, if present.
*/
-void timestamp( char * target, time_t * time )
+void timestamp( OBJECT * target, time_t * time )
{
PROFILE_ENTER( timestamp );
PATHNAME f1;
PATHNAME f2;
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
string buf[ 1 ];
-#ifdef DOWNSHIFT_PATHS
- string path;
- char * p;
-#endif
-#ifdef DOWNSHIFT_PATHS
- string_copy( &path, target );
- p = path.value;
+ target = path_as_key( target );
- do
- {
- *p = tolower( *p );
-#ifdef NT
- /* On NT, we must use backslashes or the file will not be found. */
- if ( *p == '/' )
- *p = PATH_DELIM;
-#endif
- }
- while ( *p++ );
-
- target = path.value;
-#endif /* #ifdef DOWNSHIFT_PATHS */
string_new( buf );
if ( !bindhash )
bindhash = hashinit( sizeof( BINDING ), "bindings" );
/* Quick path - is it there? */
- b->name = target;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, target, &found );
+ if ( !found )
+ {
+ b->name = object_copy( target ); /* never freed */
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( b->progress != BIND_INIT )
goto afterscanning;
@@ -115,37 +98,44 @@ void timestamp( char * target, time_t * time )
b->progress = BIND_NOENTRY;
/* Not found - have to scan for it. */
- path_parse( target, &f1 );
+ path_parse( object_str( target ), &f1 );
/* Scan directory if not already done so. */
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
path_parent( &f2 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, name, &found );
+ if ( !found )
+ {
+ b->name = object_copy( name );
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( !( b->flags & BIND_SCANNED ) )
{
- file_dirscan( buf->value, time_enter, bindhash );
+ file_dirscan( name, time_enter, bindhash );
b->flags |= BIND_SCANNED;
}
+
+ object_free( name );
}
/* Scan archive if not already done so. */
if ( f1.f_member.len )
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
@@ -153,18 +143,23 @@ void timestamp( char * target, time_t * time )
string_truncate( buf, 0 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, name, &found );
+ if ( !found )
+ {
+ b->name = object_copy( name );
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( !( b->flags & BIND_SCANNED ) )
{
file_archscan( buf->value, time_enter, bindhash );
b->flags |= BIND_SCANNED;
}
+
+ object_free( name );
}
afterscanning:
@@ -178,43 +173,41 @@ void timestamp( char * target, time_t * time )
*time = b->progress == BIND_FOUND ? b->time : 0;
string_free( buf );
-#ifdef DOWNSHIFT_PATHS
- string_free( &path );
-#endif
+
+ object_free( target );
PROFILE_EXIT( timestamp );
}
-static void time_enter( void * closure, char * target, int found, time_t time )
+static void time_enter( void * closure, OBJECT * target, int found, time_t time )
{
- BINDING binding;
- BINDING * b = &binding;
+ int item_found;
+ BINDING * b;
struct hash * bindhash = (struct hash *)closure;
-#ifdef DOWNSHIFT_PATHS
- char path[ MAXJPATH ];
- char * p = path;
-
- do *p++ = tolower( *target );
- while ( *target++ );
-
- target = path;
-#endif
-
- b->name = target;
- b->flags = 0;
+ target = path_as_key( target );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, target, &item_found );
+ if ( !item_found )
+ {
+ b->name = object_copy( target );
+ b->flags = 0;
+ }
b->time = time;
b->progress = found ? BIND_FOUND : BIND_SPOTTED;
if ( DEBUG_BINDSCAN )
- printf( "time ( %s ) : %s\n", target, time_progress[ b->progress ] );
+ printf( "time ( %s ) : %s\n", object_str( target ), time_progress[ b->progress ] );
+
+ object_free( target );
}
+static void free_timestamps ( void * xbinding, void * data )
+{
+ object_free( ((BINDING *)xbinding)->name );
+}
/*
* stamps_done() - free timestamp tables.
@@ -222,5 +215,9 @@ static void time_enter( void * closure, char * target, int found, time_t time )
void stamps_done()
{
- hashdone( bindhash );
+ if ( bindhash )
+ {
+ hashenumerate( bindhash, free_timestamps, (void *)0 );
+ hashdone( bindhash );
+ }
}
diff --git a/tools/build/v2/engine/timestamp.h b/tools/build/v2/engine/timestamp.h
index f575276393..26b7e8d1c9 100644
--- a/tools/build/v2/engine/timestamp.h
+++ b/tools/build/v2/engine/timestamp.h
@@ -8,5 +8,13 @@
* timestamp.h - get the timestamp of a file or archive member
*/
-void timestamp( char * target, time_t * time );
+#ifndef TIMESTAMP_H_SW_2011_11_18
+#define TIMESTAMP_H_SW_2011_11_18
+
+#include "object.h"
+#include "time.h"
+
+void timestamp( OBJECT * target, time_t * time );
void stamps_done();
+
+#endif
diff --git a/tools/build/v2/engine/variable.c b/tools/build/v2/engine/variable.c
index 795f345846..21eedf395a 100644
--- a/tools/build/v2/engine/variable.c
+++ b/tools/build/v2/engine/variable.c
@@ -16,12 +16,12 @@
#include "lists.h"
#include "parse.h"
#include "variable.h"
-#include "expand.h"
#include "hash.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "strings.h"
#include "pathsys.h"
+#include "modules.h"
#include <stdlib.h>
#include <stdio.h>
@@ -49,8 +49,6 @@
* 09/11/00 (seiwald) - defunct var_list() removed
*/
-static struct hash *varhash = 0;
-
/*
* VARIABLE - a user defined multi-value variable
*/
@@ -59,26 +57,12 @@ typedef struct _variable VARIABLE ;
struct _variable
{
- char * symbol;
- LIST * value;
+ OBJECT * symbol;
+ LIST * value;
};
-static VARIABLE * var_enter( char * symbol );
-static void var_dump( char * symbol, LIST * value, char * what );
-
-
-/*
- * var_hash_swap() - swap all variable settings with those passed
- *
- * Used to implement separate settings spaces for modules
- */
-
-void var_hash_swap( struct hash * * new_vars )
-{
- struct hash * old = varhash;
- varhash = *new_vars;
- *new_vars = old;
-}
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol );
+static void var_dump( OBJECT * symbol, LIST * value, char * what );
/*
@@ -94,7 +78,7 @@ void var_hash_swap( struct hash * * new_vars )
* Otherwise, split the value at blanks.
*/
-void var_defines( char * const * e, int preprocess )
+void var_defines( struct module_t * module, char * const * e, int preprocess )
{
string buf[1];
@@ -103,6 +87,7 @@ void var_defines( char * const * e, int preprocess )
for ( ; *e; ++e )
{
char * val;
+ OBJECT * varname;
# ifdef OS_MAC
/* On the mac (MPW), the var=val is actually var\0val */
@@ -133,7 +118,7 @@ void var_defines( char * const * e, int preprocess )
if ( quoted && preprocess )
{
string_append_range( buf, val + 2, val + len );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
else
@@ -156,16 +141,18 @@ void var_defines( char * const * e, int preprocess )
)
{
string_append_range( buf, pp, p );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
- l = list_new( l, newstr( pp ) );
+ l = list_push_back( l, object_new( pp ) );
}
/* Get name. */
string_append_range( buf, *e, val );
- var_set( buf->value, l, VAR_SET );
+ varname = object_new( buf->value );
+ var_set( module, varname, l, VAR_SET );
+ object_free( varname );
string_truncate( buf, 0 );
}
}
@@ -173,304 +160,7 @@ void var_defines( char * const * e, int preprocess )
}
-/*
- * var_string() - expand a string with variables in it
- *
- * Copies in to out; doesn't modify targets & sources.
- */
-
-int var_string( char * in, char * out, int outsize, LOL * lol )
-{
- char * out0 = out;
- char * oute = out + outsize - 1;
-
- while ( *in )
- {
- char * lastword;
- int dollar = 0;
-
- /* Copy white space. */
- while ( isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
- *out++ = *in++;
- }
-
- lastword = out;
-
- /* Copy non-white space, watching for variables. */
- while ( *in && !isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
-
- if ( ( in[ 0 ] == '$' ) && ( in[ 1 ] == '(' ) )
- {
- ++dollar;
- *out++ = *in++;
- }
- #ifdef OPT_AT_FILES
- else if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) )
- {
- int depth = 1;
- char * ine = in + 2;
- char * split = 0;
-
- /* Scan the content of the response file @() section. */
- while ( *ine && ( depth > 0 ) )
- {
- switch ( *ine )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- case ':':
- if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
- split = ine;
- break;
- }
- ++ine;
- }
-
- if ( !split )
- {
- /* the @() reference doesn't match the @(foo:E=bar) format.
- hence we leave it alone by copying directly to output. */
- int l = 0;
- if ( out + 2 >= oute ) return -1;
- *( out++ ) = '@';
- *( out++ ) = '(';
- l = var_string( in + 2, out, oute - out, lol );
- if ( l < 0 ) return -1;
- out += l;
- if ( out + 1 >= oute ) return -1;
- *( out++ ) = ')';
- }
- else if ( depth == 0 )
- {
- string file_name_v;
- int file_name_l = 0;
- const char * file_name_s = 0;
-
- /* Expand the temporary file name var inline. */
- #if 0
- string_copy( &file_name_v, "$(" );
- string_append_range( &file_name_v, in + 2, split );
- string_push_back( &file_name_v, ')' );
- #else
- string_new( &file_name_v );
- string_append_range( &file_name_v, in + 2, split );
- #endif
- file_name_l = var_string( file_name_v.value, out, oute - out + 1, lol );
- string_free( &file_name_v );
- if ( file_name_l < 0 ) return -1;
- file_name_s = out;
-
- /* For stdout/stderr we will create a temp file and generate
- * a command that outputs the content as needed.
- */
- if ( ( strcmp( "STDOUT", out ) == 0 ) ||
- ( strcmp( "STDERR", out ) == 0 ) )
- {
- int err_redir = strcmp( "STDERR", out ) == 0;
- out[ 0 ] = '\0';
- file_name_s = path_tmpfile();
- file_name_l = strlen(file_name_s);
- #ifdef OS_NT
- if ( ( out + 7 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"type \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #else
- if ( ( out + 6 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"cat \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #endif
- /* We also make sure that the temp files created by this
- * get nuked eventually.
- */
- file_remove_atexit( file_name_s );
- }
-
- /* Expand the file value into the file reference. */
- var_string_to_file( split + 3, ine - split - 4, file_name_s,
- lol );
-
- /* Continue on with the expansion. */
- out += strlen( out );
- }
-
- /* And continue with the parsing just past the @() reference. */
- in = ine;
- }
- #endif
- else
- {
- *out++ = *in++;
- }
- }
-
- /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
- if ( out >= oute )
- return -1;
- /* Do not increment, intentionally. */
- *out = '\0';
-
- /* If a variable encountered, expand it and and embed the
- * space-separated members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, lastword, out, lol, 0 );
-
- out = lastword;
-
- while ( l )
- {
- int so = strlen( l->string );
-
- if ( out + so >= oute )
- return -1;
-
- strcpy( out, l->string );
- out += so;
- l = list_next( l );
- if ( l ) *out++ = ' ';
- }
-
- list_free( l );
- }
- }
-
- if ( out >= oute )
- return -1;
-
- *out++ = '\0';
-
- return out - out0;
-}
-
-
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol )
-{
- char const * ine = in + insize;
- FILE * out_file = 0;
- int out_debug = DEBUG_EXEC ? 1 : 0;
- if ( globs.noexec )
- {
- /* out_debug = 1; */
- }
- else if ( strcmp( out, "STDOUT" ) == 0 )
- {
- out_file = stdout;
- }
- else if ( strcmp( out, "STDERR" ) == 0 )
- {
- out_file = stderr;
- }
- else
- {
- /* Handle "path to file" filenames. */
- string out_name;
- if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) )
- {
- string_copy( &out_name, out + 1 );
- string_truncate( &out_name, out_name.size - 1 );
- }
- else
- {
- string_copy( &out_name,out );
- }
- out_file = fopen( out_name.value, "w" );
- if ( !out_file )
- {
- printf( "failed to write output file '%s'!\n", out_name.value );
- exit( EXITBAD );
- }
- string_free( &out_name );
- }
-
- if ( out_debug ) printf( "\nfile %s\n", out );
-
- while ( *in && ( in < ine ) )
- {
- int dollar = 0;
- const char * output_0 = in;
- const char * output_1 = in;
-
- /* Copy white space. */
- while ( ( output_1 < ine ) && isspace( *output_1 ) )
- ++output_1;
-
- if ( output_0 < output_1 )
- {
- if ( out_file ) fwrite( output_0, output_1 - output_0, 1, out_file );
- if ( out_debug ) fwrite( output_0, output_1 - output_0, 1, stdout );
- }
- output_0 = output_1;
-
- /* Copy non-white space, watching for variables. */
- while ( ( output_1 < ine ) && *output_1 && !isspace( *output_1 ) )
- {
- if ( ( output_1[ 0 ] == '$' ) && ( output_1[ 1 ] == '(' ) )
- ++dollar;
- ++output_1;
- }
-
- /* If a variable encountered, expand it and embed the space-separated
- * members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, (char *)output_0, (char *)output_1, lol, 0 );
-
- while ( l )
- {
- if ( out_file ) fputs( l->string, out_file );
- if ( out_debug ) puts( l->string );
- l = list_next( l );
- if ( l )
- {
- if ( out_file ) fputc( ' ', out_file );
- if ( out_debug ) fputc( ' ', stdout );
- }
- }
-
- list_free( l );
- }
- else if ( output_0 < output_1 )
- {
- if ( out_file )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, out_file );
- }
- }
- if ( out_debug )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, stdout );
- }
- }
- }
-
- in = output_1;
- }
-
- if ( out_file && ( out_file != stdout ) && ( out_file != stderr ) )
- {
- fflush( out_file );
- fclose( out_file );
- }
-
- if ( out_debug ) fputc( '\n', stdout );
-}
-
+static LIST * saved_var = L0;
/*
* var_get() - get value of a user defined symbol.
@@ -478,40 +168,49 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
* Returns NULL if symbol unset.
*/
-LIST * var_get( char * symbol )
+LIST * var_get( struct module_t * module, OBJECT * symbol )
{
- LIST * result = 0;
+ LIST * result = L0;
#ifdef OPT_AT_FILES
/* Some "fixed" variables... */
- if ( strcmp( "TMPDIR", symbol ) == 0 )
+ if ( object_equal( symbol, constant_TMPDIR ) )
{
- result = list_new( L0, newstr( (char *)path_tmpdir() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_new( path_tmpdir() ) );
}
- else if ( strcmp( "TMPNAME", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPNAME ) )
{
- result = list_new( L0, newstr( (char *)path_tmpnam() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpnam() );
}
- else if ( strcmp( "TMPFILE", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPFILE ) )
{
- result = list_new( L0, newstr( (char *)path_tmpfile() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpfile() );
}
- else if ( strcmp( "STDOUT", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDOUT ) )
{
- result = list_new( L0, newstr( "STDOUT" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDOUT ) );
}
- else if ( strcmp( "STDERR", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDERR ) )
{
- result = list_new( L0, newstr( "STDERR" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDERR ) );
}
else
#endif
{
- VARIABLE var;
- VARIABLE * v = &var;
+ VARIABLE * v;
+ int n;
- v->symbol = symbol;
-
- if ( varhash && hashcheck( varhash, (HASHDATA * *)&v ) )
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ if ( DEBUG_VARGET )
+ var_dump( symbol, module->fixed_variables[ n ], "get" );
+ result = module->fixed_variables[ n ];
+ }
+ else if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
{
if ( DEBUG_VARGET )
var_dump( v->symbol, v->value, "get" );
@@ -522,6 +221,20 @@ LIST * var_get( char * symbol )
}
+LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
+{
+ LIST * result = L0;
+ VARIABLE * v;
+
+ if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ {
+ result = v->value;
+ v->value = L0;
+ }
+
+ return result;
+}
+
/*
* var_set() - set a variable in Jam's user defined symbol table.
*
@@ -532,9 +245,9 @@ LIST * var_get( char * symbol )
* Copies symbol. Takes ownership of value.
*/
-void var_set( char * symbol, LIST * value, int flag )
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag )
{
- VARIABLE * v = var_enter( symbol );
+ LIST * * v = var_enter( module, symbol );
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
@@ -543,19 +256,19 @@ void var_set( char * symbol, LIST * value, int flag )
{
case VAR_SET:
/* Replace value */
- list_free( v->value );
- v->value = value;
+ list_free( *v );
+ *v = value;
break;
case VAR_APPEND:
/* Append value */
- v->value = list_append( v->value, value );
+ *v = list_append( *v, value );
break;
case VAR_DEFAULT:
/* Set only if unset */
- if ( !v->value )
- v->value = value;
+ if ( list_empty( *v ) )
+ *v = value;
else
list_free( value );
break;
@@ -567,13 +280,13 @@ void var_set( char * symbol, LIST * value, int flag )
* var_swap() - swap a variable's value with the given one.
*/
-LIST * var_swap( char * symbol, LIST * value )
+LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
{
- VARIABLE * v = var_enter( symbol );
- LIST * oldvalue = v->value;
+ LIST * * v = var_enter( module, symbol );
+ LIST * oldvalue = *v;
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
- v->value = value;
+ *v = value;
return oldvalue;
}
@@ -582,21 +295,28 @@ LIST * var_swap( char * symbol, LIST * value )
* var_enter() - make new var symbol table entry, returning var ptr.
*/
-static VARIABLE * var_enter( char * symbol )
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
{
- VARIABLE var;
- VARIABLE * v = &var;
+ int found;
+ VARIABLE * v;
+ int n;
- if ( !varhash )
- varhash = hashinit( sizeof( VARIABLE ), "variables" );
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ return &module->fixed_variables[ n ];
+ }
- v->symbol = symbol;
- v->value = 0;
+ if ( !module->variables )
+ module->variables = hashinit( sizeof( VARIABLE ), "variables" );
- if ( hashenter( varhash, (HASHDATA * *)&v ) )
- v->symbol = newstr( symbol ); /* never freed */
+ v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
+ if ( !found )
+ {
+ v->symbol = object_copy( symbol );
+ v->value = L0;
+ }
- return v;
+ return &v->value;
}
@@ -604,9 +324,9 @@ static VARIABLE * var_enter( char * symbol )
* var_dump() - dump a variable to stdout.
*/
-static void var_dump( char * symbol, LIST * value, char * what )
+static void var_dump( OBJECT * symbol, LIST * value, char * what )
{
- printf( "%s %s = ", what, symbol );
+ printf( "%s %s = ", what, object_str( symbol ) );
list_print( value );
printf( "\n" );
}
@@ -619,13 +339,15 @@ static void var_dump( char * symbol, LIST * value, char * what )
static void delete_var_( void * xvar, void * data )
{
VARIABLE * v = (VARIABLE *)xvar;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v-> value );
}
-void var_done()
+void var_done( struct module_t * module )
{
- hashenumerate( varhash, delete_var_, (void *)0 );
- hashdone( varhash );
+ list_free( saved_var );
+ saved_var = L0;
+ hashenumerate( module->variables, delete_var_, (void *)0 );
+ hash_free( module->variables );
}
diff --git a/tools/build/v2/engine/variable.h b/tools/build/v2/engine/variable.h
index 5c49e3ca55..aa27d56d6b 100644
--- a/tools/build/v2/engine/variable.h
+++ b/tools/build/v2/engine/variable.h
@@ -8,22 +8,16 @@
* variable.h - handle jam multi-element variables
*/
-struct hash;
+#ifndef VARIABLE_SW20111119_H
+#define VARIABLE_SW20111119_H
-void var_defines( char* const *e, int preprocess );
-int var_string( char *in, char *out, int outsize, LOL *lol );
-LIST * var_get( char *symbol );
-void var_set( char *symbol, LIST *value, int flag );
-LIST * var_swap( char *symbol, LIST *value );
-void var_done();
-void var_hash_swap( struct hash** );
+struct module_t;
-/** Expands the "in" expression directly into the "out" file.
- The file can be one of: a path, STDOUT, or STDERR to send
- the output to a file overwriting previous content, to
- the console, or to the error output respectively.
-*/
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol );
+void var_defines( struct module_t * module, char * const * e, int preprocess );
+LIST * var_get( struct module_t * module, OBJECT * symbol );
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag );
+LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value );
+void var_done( struct module_t * module );
/*
* Defines for var_set().
@@ -33,3 +27,4 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
# define VAR_APPEND 1 /* append to previous value */
# define VAR_DEFAULT 2 /* set only if no previous value */
+#endif
diff --git a/tools/build/v2/engine/w32_getreg.c b/tools/build/v2/engine/w32_getreg.c
index 5a06f43e92..dd2d0fc70c 100644
--- a/tools/build/v2/engine/w32_getreg.c
+++ b/tools/build/v2/engine/w32_getreg.c
@@ -9,7 +9,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# if defined( OS_NT ) || defined( OS_CYGWIN )
# include "lists.h"
-# include "newstr.h"
+# include "object.h"
# include "parse.h"
# include "frames.h"
# include "strings.h"
@@ -57,12 +57,9 @@ static HKEY get_key(char const** path)
return p->value;
}
-LIST*
-builtin_system_registry(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
LIST* result = L0;
HKEY key = get_key(&path);
@@ -74,10 +71,10 @@ builtin_system_registry(
DWORD type;
BYTE data[MAX_REGISTRY_DATA_LENGTH];
DWORD len = sizeof(data);
- LIST const* const field = lol_get(frame->args, 1);
+ LIST * const field = lol_get(frame->args, 1);
if ( ERROR_SUCCESS ==
- RegQueryValueEx(key, field ? field->string : 0, 0, &type, data, &len) )
+ RegQueryValueEx(key, field ? object_str( list_front( field ) ) : 0, 0, &type, data, &len) )
{
switch (type)
{
@@ -97,7 +94,7 @@ builtin_system_registry(
expanded->size = len - 1;
- result = list_new( result, newstr(expanded->value) );
+ result = list_push_back( result, object_new(expanded->value) );
string_free( expanded );
}
break;
@@ -107,7 +104,7 @@ builtin_system_registry(
char* s;
for (s = (char*)data; *s; s += strlen(s) + 1)
- result = list_new( result, newstr(s) );
+ result = list_push_back( result, object_new(s) );
}
break;
@@ -116,12 +113,12 @@ builtin_system_registry(
{
char buf[100];
sprintf( buf, "%u", *(PDWORD)data );
- result = list_new( result, newstr(buf) );
+ result = list_push_back( result, object_new(buf) );
}
break;
case REG_SZ:
- result = list_new( result, newstr((char*)data) );
+ result = list_push_back( result, object_new( (const char *)data ) );
break;
}
}
@@ -151,7 +148,7 @@ static LIST* get_subkey_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -178,7 +175,7 @@ static LIST* get_value_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -187,13 +184,10 @@ static LIST* get_value_names(HKEY key, char const* path)
return result;
}
-LIST*
-builtin_system_registry_names(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry_names( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
- char const* result_type = lol_get(frame->args, 1)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
+ char const* result_type = object_str( list_front( lol_get(frame->args, 1) ) );
HKEY key = get_key(&path);
diff --git a/tools/build/v2/test/BoostBuild.py b/tools/build/v2/test/BoostBuild.py
index 409a51b6e9..9ad9202877 100644
--- a/tools/build/v2/test/BoostBuild.py
+++ b/tools/build/v2/test/BoostBuild.py
@@ -76,19 +76,30 @@ def get_toolset():
# Detect the host OS.
windows = False
-if os.environ.get('OS', '').lower().startswith('windows') or \
- os.__dict__.has_key('uname') and \
- os.uname()[0].lower().startswith('cygwin'):
+cygwin = False
+if os.environ.get('OS', '').lower().startswith('windows'):
windows = True
+if os.__dict__.has_key('uname') and \
+ os.uname()[0].lower().startswith('cygwin'):
+ windows = True
+ cygwin = True
suffixes = {}
+# Configuration stating whether Boost Build is expected to automatically prepend
+# prefixes to built library targets.
+lib_prefix = "lib"
+dll_prefix = "lib"
+
# Prepare the map of suffixes
def prepare_suffix_map(toolset):
global windows
global suffixes
+ global cygwin
+ global lib_prefix
+ global dll_prefix
suffixes = {'.exe': '', '.dll': '.so', '.lib': '.a', '.obj': '.o'}
suffixes['.implib'] = '.no_implib_files_on_this_platform'
if windows:
@@ -96,9 +107,19 @@ def prepare_suffix_map(toolset):
if toolset in ["gcc"]:
suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
suffixes['.obj'] = '.o'
- suffixes['.implib'] = '.lib'
+ if cygwin:
+ suffixes['.implib'] = '.lib.a'
+ else:
+ suffixes['.implib'] = '.lib'
if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
suffixes['.dll'] = '.dylib'
+
+ lib_prefix = "lib"
+ dll_prefix = "lib"
+ if cygwin:
+ dll_prefix = "cyg"
+ elif windows and not toolset in ["gcc"]:
+ dll_prefix = None
def re_remove(sequence, regex):
@@ -118,13 +139,6 @@ def glob_remove(sequence, pattern):
sequence.remove(r)
-# Configuration stating whether Boost Build is expected to automatically prepend
-# prefixes to built library targets.
-lib_prefix = True
-dll_prefix = True
-if windows:
- dll_prefix = False
-
#
# FIXME: this is copy-pasted from TestSCons.py
@@ -192,7 +206,7 @@ class Tester(TestCmd.TestCmd):
def __init__(self, arguments="", executable="bjam",
match=TestCmd.match_exact, boost_build_path=None,
translate_suffixes=True, pass_toolset=True, use_test_config=True,
- ignore_toolset_requirements=True, workdir="", **keywords):
+ ignore_toolset_requirements=True, workdir="", pass_d0=True, **keywords):
self.original_workdir = os.getcwd()
if workdir != '' and not os.path.isabs(workdir):
@@ -259,6 +273,8 @@ class Tester(TestCmd.TestCmd):
sys.exit(1)
verbosity = ['-d0', '--quiet']
+ if not pass_d0:
+ verbosity = []
if '--verbose' in sys.argv:
keywords['verbose'] = True
verbosity = ['-d+2']
@@ -365,9 +381,16 @@ class Tester(TestCmd.TestCmd):
os.utime(self.native_file_name(name), None)
def rm(self, names):
- self.wait_for_time_change_since_last_build()
if not type(names) == types.ListType:
names = [names]
+
+ if names == ["."]:
+ # If we're deleting the entire workspace, there's no
+ # need to wait for a clock tick.
+ self.last_build_time_start = 0
+ self.last_build_time_finish = 0
+
+ self.wait_for_time_change_since_last_build()
# Avoid attempts to remove the current directory.
os.chdir(self.original_workdir)
@@ -495,6 +518,10 @@ class Tester(TestCmd.TestCmd):
self.tree = tree.build_tree(self.workdir)
self.difference = tree.trees_difference(self.previous_tree, self.tree)
+ if self.difference.empty():
+ # If nothing was changed, there's no need to wait
+ self.last_build_time_start = 0
+ self.last_build_time_finish = 0
self.difference.ignore_directories()
self.unexpected_difference = copy.deepcopy(self.difference)
@@ -795,6 +822,7 @@ class Tester(TestCmd.TestCmd):
def adjust_lib_name(self, name):
global lib_prefix
+ global dll_prefix
result = name
pos = string.rfind(name, ".")
@@ -803,12 +831,12 @@ class Tester(TestCmd.TestCmd):
if suffix == ".lib":
(head, tail) = os.path.split(name)
if lib_prefix:
- tail = "lib" + tail
+ tail = lib_prefix + tail
result = os.path.join(head, tail)
elif suffix == ".dll":
(head, tail) = os.path.split(name)
if dll_prefix:
- tail = "lib" + tail
+ tail = dll_prefix + tail
result = os.path.join(head, tail)
# If we want to use this name in a Jamfile, we better convert \ to /, as
# otherwise we would have to quote \.
diff --git a/tools/build/v2/test/Jamrules b/tools/build/v2/test/Jamrules
deleted file mode 100644
index ff29a26bba..0000000000
--- a/tools/build/v2/test/Jamrules
+++ /dev/null
@@ -1,4 +0,0 @@
-# This simple Jamrules file is used for the Boost.Build test project.
-
-# The testing framework itself gets no boost-Jambase
-BOOST_JAMBASE = empty.jam ;
diff --git a/tools/build/v2/test/absolute_sources.py b/tools/build/v2/test/absolute_sources.py
index 58e2cf4516..4053b35ca1 100644
--- a/tools/build/v2/test/absolute_sources.py
+++ b/tools/build/v2/test/absolute_sources.py
@@ -26,6 +26,7 @@ t.write("empty.cpp", "\n")
t.run_build_system()
t.expect_addition("bin/$toolset/debug/hello.exe")
+t.rm(".")
# Test a contrived case. There, absolute name is used in a standalone project
# (not Jamfile). Moreover, the target with an absolute name is returned by
diff --git a/tools/build/v2/test/assert-equal.jam b/tools/build/v2/test/assert-equal.jam
deleted file mode 100644
index 6ed501e74b..0000000000
--- a/tools/build/v2/test/assert-equal.jam
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Evaluates [ rulename arg1... : arg2... : ... : argN... ] and compares the
-# result to expected-results. If there is a mismatch, prints an error message
-# and exits.
-rule assert-equal ( expected-results *
- : rulename a1 * : a2 * : a3 * : a4 * : a5 * : a6 * : a7 * : a8 * : a9 * )
-{
-
- local results = [ $(rulename) $(a1) : $(a2) : $(a3)
- : $(a4) : $(a5) : $(a6) : $(a7) : $(a8) ] ;
-
- if $(results) != $(expected-results)
- {
- EXIT ******ASSERTION FAILURE******* "
- [ $(rulename) " $(a1)
- ": "$(a2[1]) $(a2[2-])
- ": "$(a3[1]) $(a3[2-])
- ": "$(a4[1]) $(a4[2-])
- ": "$(a5[1]) $(a5[2-])
- ": "$(a6[1]) $(a6[2-])
- ": "$(a7[1]) $(a7[2-])
- ": "$(a8[1]) $(a8[2-]) "]
-expected:
- (" $(expected-results) ")
-result was:
- (" $(results) ")"
- ;
-
- }
-}
diff --git a/tools/build/v2/test/builtin_echo.py b/tools/build/v2/test/builtin_echo.py
new file mode 100755
index 0000000000..4d57e96bfc
--- /dev/null
+++ b/tools/build/v2/test/builtin_echo.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+# Copyright 2012 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+# This tests the ECHO rule.
+
+import BoostBuild
+
+def test_echo(name):
+ t = BoostBuild.Tester(pass_toolset=0)
+
+ t.write("file.jam", """
+ %s ;
+ UPDATE ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="\n")
+
+ t.write("file.jam", """
+ %s a message ;
+ UPDATE ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="a message\n")
+
+ t.cleanup()
+
+test_echo("ECHO")
+test_echo("Echo")
+test_echo("echo")
diff --git a/tools/build/v2/test/builtin_exit.py b/tools/build/v2/test/builtin_exit.py
new file mode 100755
index 0000000000..2e4fd1215c
--- /dev/null
+++ b/tools/build/v2/test/builtin_exit.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+
+# Copyright 2012 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+# This tests the EXIT rule.
+
+import BoostBuild
+
+def test_exit(name):
+ t = BoostBuild.Tester(pass_toolset=0)
+
+ t.write("file.jam", """
+ %s ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 0 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 1 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 2 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=2, stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s a message ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=1, stdout="a message\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s a message : 0 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="a message\n")
+ t.rm(".")
+
+ t.cleanup()
+
+test_exit("EXIT")
+test_exit("Exit")
+test_exit("exit")
diff --git a/tools/build/v2/test/check-arguments.jam b/tools/build/v2/test/check-arguments.jam
deleted file mode 100644
index 20e025074d..0000000000
--- a/tools/build/v2/test/check-arguments.jam
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-#
-# Jam code for testing the named-argument patch.
-#
-
-include recursive.jam ;
-
-# Prefixes for all of the jam code we're going to test
-local ECHO_ARGS = "include echo_args.jam ; echo_args "
- ;
-
-local ECHO_VARARGS = "include echo_args.jam ; echo_varargs "
- ;
-
-# Check that it will find missing arguments
-Jam-fail $(ECHO_ARGS)";"
- : "missing argument a"
- ;
-
-# Check that it will find if too many arguments are passed
-Jam-fail $(ECHO_ARGS)"1 2 : 3 : 4 : 5 ;"
- : "extra argument 5"
- ;
-
-# Check that it will find when an argument has too many elements
-Jam-fail $(ECHO_ARGS)"a b c1 c2 : d ;"
- : "extra argument c2"
- ;
-
-# Check modifier '?'
-Jam $(ECHO_ARGS)"1 2 3 : 4 ;"
- : "a= 1 b= 2 c= 3 : d= 4 : e=" ;
-Jam $(ECHO_ARGS)"1 2 : 3 ;"
- : "a= 1 b= 2 c= : d= 3 : e=" ;
-Jam $(ECHO_ARGS)"1 : 2 ;"
- : "a= 1 b= c= : d= 2 : e=" ;
-
-# Check modifier '+'
-Jam-fail $(ECHO_ARGS)"1 ;"
- : "missing argument d" ;
-Jam $(ECHO_ARGS)"1 : 2 3 ;"
- : "a= 1 b= c= : d= 2 3 : e=" ;
-Jam $(ECHO_ARGS)"1 : 2 3 4 ;"
- : "a= 1 b= c= : d= 2 3 4 : e=" ;
-
-# Check modifier '*'
-Jam $(ECHO_ARGS)"1 : 2 : 3 ;"
- : "a= 1 b= c= : d= 2 : e= 3" ;
-Jam $(ECHO_ARGS)"1 : 2 : 3 4 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4" ;
-Jam $(ECHO_ARGS)"1 : 2 : 3 4 5 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5" ;
-
-#
-# Check varargs
-#
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 : 8 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 : 8 : 9 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9" ;
-
-
diff --git a/tools/build/v2/test/check-jam-patches.jam b/tools/build/v2/test/check-jam-patches.jam
deleted file mode 100644
index 7e00bec20c..0000000000
--- a/tools/build/v2/test/check-jam-patches.jam
+++ /dev/null
@@ -1,293 +0,0 @@
-# Copyright 2001, 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Get the recursive Jam invocation code
-include recursive.jam ;
-include assert-equal.jam ;
-
-Jam "include check-bindrule.jam ;"
- : "found: file-to-bind at subdir1$(SLASH)file-to-bind"
- ;
-
-include check-arguments.jam ;
-
-if $(NT)
-{
- # if this one fails, you don't have the line length patch
- Jam "include test_nt_line_length.jam ;" ;
-}
-
-# a little utility for assertions
-rule identity ( list * )
-{
- return $(list) ;
-}
-
-#
-# test rule indirection
-#
-rule select ( n list * )
-{
- return $(list[$(n)]) ;
-}
-
-rule indirect1 ( rule + : args * )
-{
- return [ $(rule) $(args) ] ;
-}
-
-assert-equal a : indirect1 select 1 : a b c d e ;
-assert-equal b : indirect1 select 2 : a b c d e ;
-
-x = reset ;
-rule reset-x ( new-value )
-{
- x = $(new-value) ;
-}
-$(x)-x bar ; # invokes reset-x...
-assert-equal bar : identity $(x) ; # which changes x
-
-# Check that unmatched subst returns an empty list
-assert-equal # nothing
- : SUBST "abc" "d+" x ;
-
-# Check that a matched subst works
-assert-equal x
- : SUBST "ddd" "d+" x ;
-
-# Check that we can get multiple substitutions from a single invocation
-assert-equal x y x-y
- : SUBST "x/y/z" "([^/]*)/([^/]*).*" "\\1" $2 "\\1-\\2" ;
-
-#
-# test local foreach modification
-#
-{
- local x = 0 ;
- local entered = ;
- for local x in a b c # x declared local to for loop.
- {
- entered = 1 ;
- if ! ( $(x) in a b c )
- {
- EXIT "local foreach: expected one of a, b, c; got" $(x) ;
- }
- }
-
- if $(x) != 0 # if x was modified, it failed to be a local variable
- {
- EXIT "local foreach failed" ;
- }
-}
-
-#
-# test while loops
-#
-{
- local x = a b c ;
- local y = $(x) ;
- local z = ;
-
- while $(y)
- {
- z += $(y[1]) ;
- y = $(y[2-]) ;
- }
-
- if $(z) != $(x)
- {
- EXIT "while loops failed" ;
- }
-}
-
-#
-# test negative list indices and slices
-#
-{
- local x = a b c d e ;
-
- rule assert-index ( index : list * )
- {
- if $(x[$(index)]) != $(list)
- {
- ECHO with x= $(x) ;
- ECHO x[$(index)] == $(x[$(index)]) ;
- EXIT expected $(list) ;
- }
- }
-
- assert-index 1 : a ;
- assert-index 3 : c ;
- assert-index 1-2 : a b ;
- assert-index -1 : e ;
- assert-index -2 : d ;
- assert-index 2--2 : b c d ;
- assert-index -3--2 : c d ;
- assert-index 1--2 : a b c d ;
- assert-index 1--2 : a b c d ;
- assert-index 1--10 : ;
- x = a ;
- assert-index 1--2 : ;
- assert-index 1--2 : ;
-}
-
-#
-# test module primitives
-#
-{
- local x = a b c d e f g h i j ;
- local y = $(x[3-]) ;
-
- rule shift1 ( dummy ) { }
-
- rule my_module.not_really ( ) { return something ; }
-
- # import the identity rule into my_module as "id"
- IMPORT : identity : my_module : id ;
- module my_module
- {
- # assert-equal operates in its own module, so call id in here and use
- # identity later.
- local f = [ id x y z ] ;
- assert-equal x y z : identity $(f) ;
-
- w = ;
- y = ;
- x2 = 1 2 3 ;
- x3 = $(x2) ;
- z = $(x2) ;
-
- x3 = ; # should reset x3
-
- # drops one element from the head of x
- # moves the first element of z from the head of z to the head of y
- rule shift1 ( )
- {
- x = $(x[2-]) ;
- y = $(z[1]) $(y) ;
- z = $(z[2-]) ;
- }
-
- rule shift2 ( )
- {
- shift1 ;
- }
-
- shift1 ;
- shift2 ;
-
- rule get ( symbol )
- {
- return $($(symbol)) ;
- }
- local rule not_really ( ) { return nothing ; }
- }
-
- local expected = shift1 shift2 get ;
- if ! ( $(expected) in [ RULENAMES my_module ] )
- || ! ( [ RULENAMES my_module ] in $(expected) )
- {
- EXIT "[ RULENAMES my_module ] =" [ RULENAMES my_module ] "!=" shift1 shift2 get ;
- }
-
-
- # show that not_really was actually a local definition
- assert-equal something : my_module.not_really ;
-
- if not_really in [ RULENAMES my_module ]
- {
- EXIT unexpectedly found local rule "not_really" in "my_module" ;
- }
- EXPORT my_module : not_really ;
-
- if ! ( not_really in [ RULENAMES my_module ] )
- {
- EXIT unexpectedly failed to find exported rule "not_really" in "my_module" ;
- }
-
- # show that my_module doesn't have access to our variables
- my_module.shift1 ;
- assert-equal $(x[3-]) : identity $(y) ;
-
- # check module locals
- assert-equal : my_module.get w ;
- assert-equal 3 2 1 : my_module.get y ;
- assert-equal 1 2 3 : my_module.get x2 ;
- assert-equal : my_module.get x3 ;
- assert-equal : my_module.get z ;
-
- my_module.shift2 ;
- x = $(x[3-]) ;
- assert-equal $(x) : identity $(y) ;
-
- # Prove that the module's rule is not exposed to the world at large without
- # qualification
- shift1 nothing ;
- assert-equal $(x) : identity $(y) ;
-
- # import my_module.shift1 into the global module as "shifty", and
- # my_module.shift2 into the global module as "shift2".
- IMPORT my_module : shift1 shift2 : : shifty shift2 ;
-
- shifty ;
- assert-equal $(x) : identity $(y) ;
-
- shift2 ;
- assert-equal $(x) : identity $(y) ;
-
- # Now do the same with localization
- IMPORT my_module : shift1 : : shifty : LOCALIZE ;
-
- shifty ;
- y = $(y[3-]) ;
- assert-equal $(x) : identity $(y) ;
-
- # import everything from my_module into the global module using
- # the same names.
- IMPORT my_module : [ RULENAMES my_module ] : : [ RULENAMES my_module ] : LOCALIZE ;
-
- shift1 ;
- y = $(y[2-]) ;
- assert-equal $(x) : identity $(y) ;
-
- shift2 ;
- y = $(y[2-]) ;
- assert-equal $(x) : identity $(y) ;
-}
-
-#
-# test CALLER_MODULE and backtrace
-#
-{
- rule backtrace ( )
- {
- local bt = [ BACKTRACE ] ;
- bt = $(bt[5-]) ;
- while $(bt)
- {
- ECHO $(bt[1]):$(bt[2]): "in" $(bt[4]) ;
- bt = $(bt[5-]) ;
- }
- }
- module module1
- {
- rule f ( )
- {
- local m = [ CALLER_MODULE ] ;
- assert-equal : identity $(m) ;
- module2.f ;
- }
-
- }
- module module2
- {
- rule f ( )
- {
- local m = [ CALLER_MODULE ] ;
- assert-equal module1 : identity $(m) ;
- backtrace ;
- }
- }
- module1.f ;
-}
diff --git a/tools/build/v2/test/check-test-tools.jam b/tools/build/v2/test/check-test-tools.jam
deleted file mode 100644
index adf78cc3b4..0000000000
--- a/tools/build/v2/test/check-test-tools.jam
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-include recursive.jam ;
-include assert-equal.jam ;
-
-#####################################
-# Test the testing tools right here #
-#####################################
-
-# This command always exits with a failure.
-Jam-fail "EXIT error ;" ;
-
-# This should fail to fail
-Jam-fail
- "include recursive.jam ; Jam-fail \"# this innocuous Jamfile should fail to fail\" ;"
- ;
-
-# the ECHO rule always has an empty result.
-Jam-fail "include assert-equal.jam ; assert-equal fubar : ECHO checking that assertions fail ;"
- : "ASSERTION FAILURE"
- ;
-
-local NOTHING = ;
-assert-equal $(NOTHING) : ECHO checking that assertions succeed ;
diff --git a/tools/build/v2/test/conditionals_multiple.py b/tools/build/v2/test/conditionals_multiple.py
index 20b6b47f7b..d58d86c27e 100755
--- a/tools/build/v2/test/conditionals_multiple.py
+++ b/tools/build/v2/test/conditionals_multiple.py
@@ -21,7 +21,7 @@ def test_multiple_conditions():
"""Basic tests for properties conditioned on multiple other properties.
"""
- t = BoostBuild.Tester("--ignore-regular-config toolset=testToolset",
+ t = BoostBuild.Tester("--user-config= --ignore-site-config toolset=testToolset",
pass_toolset=False, use_test_config=False)
t.write("testToolset.jam", """
@@ -30,6 +30,13 @@ feature.extend toolset : testToolset ;
rule init ( ) { }
""")
+ t.write("testToolset.py", """
+from b2.build import feature
+feature.extend('toolset', ["testToolset"])
+def init ( ):
+ pass
+""")
+
t.write("jamroot.jam", """
import feature ;
import notfile ;
@@ -126,7 +133,7 @@ def test_multiple_conditions_with_toolset_version():
toolset = "testToolset" ;
- t = BoostBuild.Tester("--ignore-regular-config", pass_toolset=False, use_test_config=False)
+ t = BoostBuild.Tester("--user-config= --ignore-site-config", pass_toolset=False, use_test_config=False)
t.write( toolset + ".jam", """
import feature ;
@@ -135,6 +142,14 @@ feature.subfeature toolset %(toolset)s : version : 0 1 ;
rule init ( version ? ) { }
""" % {"toolset": toolset})
+ t.write( "testToolset.py", """
+from b2.build import feature
+feature.extend('toolset', ["testToolset"])
+feature.subfeature('toolset',"testToolset","version",['0','1'])
+def init ( version ):
+ pass
+ """)
+
t.write("jamroot.jam", """
import feature ;
import notfile ;
diff --git a/tools/build/v2/test/configuration.py b/tools/build/v2/test/configuration.py
index 46adfd3c9b..1125db36bd 100755
--- a/tools/build/v2/test/configuration.py
+++ b/tools/build/v2/test/configuration.py
@@ -47,6 +47,14 @@ import feature ;
feature.extend toolset : %s ;
rule init ( ) { }
""" % toolsetName )
+
+ # Python version of same dummy toolset.
+ t.write(toolsetName + ".py", """
+from b2.build import feature
+feature.extend('toolset', ['%s'])
+def init(): pass
+""" % toolsetName )
+
t.write("jamroot.jam", "using %s ;" % toolsetName)
t.run_build_system()
diff --git a/tools/build/v2/test/core-language/test.jam b/tools/build/v2/test/core-language/test.jam
new file mode 100644
index 0000000000..24dcc2924d
--- /dev/null
+++ b/tools/build/v2/test/core-language/test.jam
@@ -0,0 +1,1353 @@
+# Copyright 2011 Steven Watanabe.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+# Tools
+
+passed = 0 ;
+failed = 0 ;
+
+rule show-result ( id : test-result )
+{
+ if ! ( --quiet in $(ARGV) )
+ {
+ ECHO $(test-result): $(id) ;
+ }
+ $(test-result) = [ CALC $($(test-result)) + 1 ] ;
+}
+
+rule check-equal ( id : values * : expected * )
+{
+ local test-result ;
+ if x$(values) = x$(expected)
+ {
+ test-result = passed ;
+ }
+ else
+ {
+ ECHO error: "[" $(values) "] != [" $(expected) "]" ;
+ test-result = failed ;
+ }
+ show-result $(id) : $(test-result) ;
+}
+
+rule mark-order ( id : result * )
+{
+ order += $(id) ;
+ return $(result) ;
+}
+
+rule check-order ( id : expected * )
+{
+ check-equal $(id) : $(order) : $(expected) ;
+ order = ;
+}
+
+# Check variable expansion
+
+{
+
+local v1 = 1 2 3 ;
+local v2 = 4 5 6 ;
+local v3 = 0 1 2 3 4 5 6 7 8 9 10 ;
+local g = g1 g2 ;
+local v4 = String/With/Mixed/Case ;
+local v5 = path\\with\\backslashes ;
+local v6 = <grist>generic/path.txt(member.txt) ;
+local v7 = <Grist1>Dir1/File1.cpp(M1.c) <Grist2>Dir2/File2.hpp(M2.c) ;
+local v8 = <Grist3>Dir3/File3.c(M3.c) <Grist4>Dir4/File4.h(M4.c) ;
+local select1 = GU BL DBST ;
+local case1 = L U ;
+local vars = 7 8 ;
+local sub = 2 1 ;
+local p0 = name ;
+local p1 = dir/name ;
+local p2 = dir/sub/name ;
+local j1 = , - ;
+
+check-equal var-product : $(v1)$(v2) : 14 15 16 24 25 26 34 35 36 ;
+
+check-equal var-set-grist : $(v1:G=grist) : <grist>1 <grist>2 <grist>3 ;
+check-equal var-set-grist-multi : $(v1:G=$(g)) : <g1>1 <g1>2 <g1>3 <g2>1 <g2>2 <g2>3 ;
+
+check-equal var-lower : $(v4:L) : string/with/mixed/case ;
+check-equal var-upper : $(v4:U) : STRING/WITH/MIXED/CASE ;
+check-equal var-LU : $(v4:LU) : STRING/WITH/MIXED/CASE ;
+check-equal var-slashes : $(v5:T) : path/with/backslashes ;
+check-equal var-grist : $(v6:G) : <grist> ;
+check-equal var-base : $(v6:B) : path ;
+check-equal var-suffix : $(v6:S) : .txt ;
+check-equal var-dir : $(v6:D) : generic ;
+check-equal var-member : $(v6:M) : (member.txt) ;
+check-equal var-multi : $(v6:$(select1)) : <GRIST> path generic/path.txt ;
+
+check-equal var-join-0 : $(:J=,) : ;
+check-equal var-join-1 : $(p0:J=,) : name ;
+check-equal var-join-3 : $(v1:J=,) : 1,2,3 ;
+check-equal var-set-grist-join : $(v1:G=grist:J=,) : <grist>1,<grist>2,<grist>3 ;
+# behavior change. In the past, a J= modifier would
+# cause only the last element of the other modifiers
+# to take effect.
+check-equal var-set-grist-multi-join : $(v1:G=$(g):J=,) : <g1>1,<g1>2,<g1>3 <g2>1,<g2>2,<g2>3 ;
+check-equal var-set-grist-multi-join-multi : $(v1:G=$(g):J=$(j1)) : <g1>1,<g1>2,<g1>3 <g1>1-<g1>2-<g1>3 <g2>1,<g2>2,<g2>3 <g2>1-<g2>2-<g2>3 ;
+
+check-equal var-D=-0 : name : $(p0:D=) ;
+check-equal var-D=-1 : name : $(p1:D=) ;
+check-equal var-D=-2 : name : $(p2:D=) ;
+check-equal var-D-0 : "" : $(p0:D) ;
+check-equal var-D-1 : dir : $(p1:D) ;
+check-equal var-D-2 : dir/sub : $(p2:D) ;
+check-equal var-S-1 : "" : $(p0:S) ;
+check-equal var-no-at-file-0 : ($(p0)) : [ MATCH ^@(.*) : "@($(p0))" ] ;
+check-equal var-no-at-file-1 : ($(p0)) : [ MATCH @(.*) : "--@($(p0))" ] ;
+
+if $(OS) = CYGWIN
+{
+ local cyg-root = $(:WE=/) ;
+ local cyg1 = /cygdrive/c/path1.txt ;
+ check-equal cygwin-to-cygdrive : $(cyg1:W) : C:\\path1.txt ;
+ local cyg2 = /bin/bash ;
+ check-equal cygwin-to-windows : $(cyg2:W) : $(cyg-root)\\bin\\bash ;
+ check-equal cygwin-combine-WT : $(cyg2:WT) : $(cyg-root)\\bin\\bash ;
+
+ local cyg3 = /home/boost/devel/trunk/bin.v2/ ; # exactly 31 characters
+ local win3 = $(cyg-root)\\home\\boost\\devel\\trunk\\bin.v2\\ ;
+ # This is is the easiest way to demonstrate a bug
+ # that used to cause undefined behavior. Longer paths
+ # resulted in a use-after-free error, which happened
+ # to work most of the time.
+ check-equal cygwin-long-WU : $(cyg3:WU) : $(win3:U) ;
+
+ local cyg-grist = <grist>$(cyg1) ;
+ check-equal cygwin-grist : $(cyg-grist:W) : <grist>\\cygdrive\\c\\path1.txt ;
+
+ check-equal cygwin-WU : $(cyg2:WU) : $(cyg-root:U)\\BIN\\BASH ;
+ # behavior change: L now consistently applied after W.
+ # used to affect all except the drive letter.
+ check-equal cygwin-WL : $(cyg2:WL) : $(cyg-root:L)\\bin\\bash ;
+}
+
+# behavior change
+check-equal var-test1 : $(v7[2]:G:L) : <grist2> ;
+
+check-equal var-multi-product-smm : $(v$(vars)[$(sub)]:G=$(g):$(case1)) :
+ <g1>dir2/file2.hpp(m2.c) <G1>DIR2/FILE2.HPP(M2.C)
+ <g2>dir2/file2.hpp(m2.c) <G2>DIR2/FILE2.HPP(M2.C)
+ <g1>dir1/file1.cpp(m1.c) <G1>DIR1/FILE1.CPP(M1.C)
+ <g2>dir1/file1.cpp(m1.c) <G2>DIR1/FILE1.CPP(M1.C)
+ <g1>dir4/file4.h(m4.c) <G1>DIR4/FILE4.H(M4.C)
+ <g2>dir4/file4.h(m4.c) <G2>DIR4/FILE4.H(M4.C)
+ <g1>dir3/file3.c(m3.c) <G1>DIR3/FILE3.C(M3.C)
+ <g2>dir3/file3.c(m3.c) <G2>DIR3/FILE3.C(M3.C)
+;
+check-equal var-nopathmods : $(:E=//) : // ;
+
+# showcases all the idiosyncracies of indexing
+# key: h = high, l = low, p = positive, m = minus, e = end.
+
+check-equal var-subscript-one-p : $(v3[3]) : 2 ;
+check-equal var-subscript-one-m : $(v3[-3]) : 8 ;
+check-equal var-subscript-one-0 : $(v3[0]) : 0 ;
+check-equal var-subscript-one-h : $(v3[20]) : ;
+check-equal var-subscript-one-l : $(v3[-20]) : 0 ;
+check-equal var-subscript-range-pp : $(v3[2-4]) : 1 2 3 ;
+check-equal var-subscript-range-pm : $(v3[2--3]) : 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-pe : $(v3[2-]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ph : $(v3[2-20]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-pl : $(v3[2--20]) : ;
+check-equal var-subscript-range-mp : $(v3[-3-10]) : 8 9 ;
+check-equal var-subscript-range-mm : $(v3[-4--2]) : 7 8 9 ;
+check-equal var-subscript-range-me : $(v3[-4-]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4-20]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4--20]) : ;
+check-equal var-subscript-range-0p : $(v3[0-2]) : 0 1 2 ;
+check-equal var-subscript-range-0m : $(v3[0--4]) : 0 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-0e : $(v3[0-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0h : $(v3[0-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0l : $(v3[0--20]) : ;
+check-equal var-subscript-range-hp : $(v3[20-4]) : ;
+check-equal var-subscript-range-hm : $(v3[20--4]) : ;
+check-equal var-subscript-range-he : $(v3[20-]) : ;
+check-equal var-subscript-range-hh : $(v3[20-20]) : ;
+check-equal var-subscript-range-hl : $(v3[20--20]) : ;
+check-equal var-subscript-range-lp : $(v3[-13-4]) : 0 1 2 3 4 5 ;
+check-equal var-subscript-range-lm : $(v3[-13--4]) : 0 1 2 3 4 5 6 7 8 9 ;
+check-equal var-subscript-range-le : $(v3[-13-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-lh : $(v3[-13-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ll : $(v3[-13--13]) : 0 ;
+check-equal var-subscript-range-empty : $(v3[4-3]) : ;
+
+}
+
+# Check rules
+
+{
+
+rule test-rule
+{
+ return $(<) - $(>) - $(1) - $(2) - $(3) - $(4) - $(5) - $(6) - $(7) - $(8) - $(9) - $(10) - $(11) - $(12) - $(13) - $(14) - $(15) - $(16) - $(17) - $(18) - $(19) ;
+}
+
+check-equal rule-arguments-numbered :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+rule test-rule
+{
+ return $(<:L) - $(>:L) - $(1:L) - $(2:L) - $(3:L) - $(4:L) - $(5:L) - $(6:L) - $(7:L) - $(8:L) - $(9:L) - $(10:L) - $(11:L) - $(12:L) - $(13:L) - $(14:L) - $(15:L) - $(16:L) - $(17:L) - $(18:L) - $(19:L) ;
+}
+
+# behavior change
+check-equal rule-arguments-numbered-lower :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+
+rule test-rule ( p1 : p2 : p3 : p4 : p5 : p6 : p7 : p8 : p9 :
+ p10 : p11 : p12 : p13 : p14 : p15 : p16 : p17 : p18 : p19 )
+
+
+{
+ return $(p1) - $(p2) - $(p3) - $(p4) - $(p5) - $(p6) - $(p7) - $(p8) - $(p9) - $(p10) - $(p11) - $(p12) - $(p13) - $(p14) - $(p15) - $(p16) - $(p17) - $(p18) - $(p19) ;
+}
+
+check-equal rule-arguments-named :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+#
+# test rule indirection
+#
+rule select ( n list * )
+{
+ return $(list[$(n)]) ;
+}
+
+rule indirect1 ( rule + : args * )
+{
+ return [ $(rule) $(args) ] ;
+}
+
+check-equal rule-indirect-1 : [ indirect1 select 1 : a b c d e ] : a ;
+check-equal rule-indirect-2 : [ indirect1 select 2 : a b c d e ] : b ;
+
+x = reset ;
+rule reset-x ( new-value )
+{
+ x = $(new-value) ;
+}
+$(x)-x bar ; # invokes reset-x...
+check-equal rule-reset : $(x) : bar ; # which changes x
+
+rule bar-x ( new-value )
+{
+ mark-order r3 ;
+}
+
+# The arguments are evaluated in forward order
+# before the rule name
+$(x)-x [ mark-order r1 : [ reset-x reset ] ] : [ mark-order r2 ] ;
+check-order rule-order : r1 r2 ;
+
+}
+
+# Check append
+
+{
+
+local value = [ mark-order r1 : v1 v2 ] [ mark-order r2 : v3 v4 ] ;
+check-equal append : $(value) : v1 v2 v3 v4 ;
+check-order append-order : r1 r2 ;
+
+}
+
+# Check foreach
+
+{
+
+local v1 = 1 2 3 ;
+local x = old ;
+local result ;
+
+for local x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-local-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-local : $(x) : old ;
+
+result = ;
+
+for x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-nonlocal-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-nonlocal : $(x) : 3 ;
+
+rule call-foreach ( values * )
+{
+ for local x in $(values)
+ {
+ return $(x) ;
+ }
+}
+
+check-equal foreach-result : [ call-foreach 1 2 3 ] : ;
+
+result = ;
+local varname = x ;
+x = old ;
+
+for local $(varname) in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-no-expand : $(result) : old + old + old + ;
+
+result = ;
+
+for local v1 in $(v1)
+{
+ result += $(v1) + ;
+}
+
+check-equal foreach-order : $(result) : 1 + 2 + 3 + ;
+
+}
+
+# Check if
+
+{
+
+if true
+{
+ mark-order r1 ;
+}
+
+check-order if-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+
+check-order if-false : ;
+
+if true
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-false : r2 ;
+
+rule test-rule
+{
+ if true
+ {
+ return result ;
+ }
+}
+
+check-equal if-true-result : [ test-rule ] : result ;
+
+rule test-rule
+{
+ local idx = 1 2 ;
+ local values = true ;
+ while $(idx)
+ {
+ local v = $(values[$(idx[1])]) ;
+ idx = $(idx[2-]) ;
+ if $(v)
+ {
+ return result ;
+ }
+ }
+}
+
+check-equal if-false-result : [ test-rule ] : ;
+
+rule test-rule
+{
+ if true
+ {
+ return r1 ;
+ }
+ else
+ {
+ return r2 ;
+ }
+}
+
+check-equal if-else-true-result : [ test-rule ] : r1 ;
+
+rule test-rule
+{
+ if $(false)
+ {
+ return r1 ;
+ }
+ else
+ {
+ return r2 ;
+ }
+}
+
+check-equal if-else-false-result : [ test-rule ] : r2 ;
+
+}
+
+# Check the evaluation of conditions
+
+{
+
+local test-result ;
+local v1 = "" "" "" ;
+local v2 = ;
+local v3 = a b c ;
+local v4 = a b c d ;
+local v5 = a b d ;
+local v6 = "" "" "" d ;
+
+rule test-comparison ( id : equal less greater )
+{
+ check-equal $(id)-empty-1 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-empty-2 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(equal) ;
+ check-equal $(id)-less-1 : [ eval-$(id) $(v3) : $(v4) ] : $(less) ;
+ check-equal $(id)-less-2 : [ eval-$(id) $(v3) : $(v5) ] : $(less) ;
+ check-equal $(id)-less-3 : [ eval-$(id) $(v4) : $(v5) ] : $(less) ;
+ check-equal $(id)-greater-1 : [ eval-$(id) $(v4) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-2 : [ eval-$(id) $(v5) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-3 : [ eval-$(id) $(v5) : $(v4) ] : $(greater) ;
+}
+
+rule eval-lt ( lhs * : rhs * )
+{
+ if $(lhs) < $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison lt : false true false ;
+
+rule eval-gt ( lhs * : rhs * )
+{
+ if $(lhs) > $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison gt : false false true ;
+
+rule eval-le ( lhs * : rhs * )
+{
+ if $(lhs) <= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison le : true true false ;
+
+rule eval-ge ( lhs * : rhs * )
+{
+ if $(lhs) >= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ge : true false true ;
+
+rule eval-eq ( lhs * : rhs * )
+{
+ if $(lhs) = $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison eq : true false false ;
+
+rule eval-ne ( lhs * : rhs * )
+{
+ if $(lhs) != $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ne : false true true ;
+
+rule eval-not-lt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) < $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-lt : true false true ;
+
+rule eval-not-gt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) > $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-gt : true true false ;
+
+rule eval-not-le ( lhs * : rhs * )
+{
+ if ! ( $(lhs) <= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-le : false false true ;
+
+rule eval-not-ge ( lhs * : rhs * )
+{
+ if ! ( $(lhs) >= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ge : false true false ;
+
+rule eval-not-eq ( lhs * : rhs * )
+{
+ if ! ( $(lhs) = $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-eq : false true true ;
+
+rule eval-not-ne ( lhs * : rhs * )
+{
+ if ! ( $(lhs) != $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ne : true false false ;
+
+local v7 = a a a a a a ;
+local v8 = c b ;
+local v9 = c d b ;
+local v10 = c a b c c b a a a ;
+
+rule test-in ( id : subset not-subset )
+{
+ check-equal $(id)-0-0 : [ eval-$(id) $(v2) : $(v2) ] : $(subset) ;
+ check-equal $(id)-0-empty : [ eval-$(id) $(v2) : $(v1) ] : $(subset) ;
+ check-equal $(id)-empty-0 : [ eval-$(id) $(v1) : $(v2) ] : $(not-subset) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(subset) ;
+ check-equal $(id)-simple : [ eval-$(id) $(v3) : $(v4) ] : $(subset) ;
+ check-equal $(id)-extra : [ eval-$(id) $(v4) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-multiple : [ eval-$(id) $(v7) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered : [ eval-$(id) $(v8) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered-extra : [ eval-$(id) $(v9) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-unordered-multiple : [ eval-$(id) $(v10) : $(v3) ] : $(subset) ;
+}
+
+rule eval-in ( lhs * : rhs * )
+{
+ if $(lhs) in $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-in "in" : true false ;
+
+rule eval-not-in ( lhs * : rhs * )
+{
+ if ! ( $(lhs) in $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-in not-in : false true ;
+
+rule test-truth-table ( id : tt tf ft ff )
+{
+ check-equal $(id)-tt : [ eval-$(id) 1 : 1 ] : $(tt) ;
+ check-equal $(id)-tf : [ eval-$(id) 1 : ] : $(tf) ;
+ check-equal $(id)-ft : [ eval-$(id) : 1 ] : $(ft) ;
+ check-equal $(id)-ff : [ eval-$(id) : ] : $(ff) ;
+}
+
+rule eval-and ( lhs ? : rhs ? )
+{
+ if $(lhs) && $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table and : true false false false ;
+
+rule eval-or ( lhs ? : rhs ? )
+{
+ if $(lhs) || $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table or : true true true false ;
+
+rule eval-not-and ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) && $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-and : false true true true ;
+
+rule eval-not-or ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) || $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-or : false false false true ;
+
+if [ mark-order r1 : test1 ] < [ mark-order r2 : test2 ] { }
+check-order lt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] > [ mark-order r2 : test2 ] { }
+check-order gt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] <= [ mark-order r2 : test2 ] { }
+check-order le-order : r1 r2 ;
+if [ mark-order r1 : test1 ] >= [ mark-order r2 : test2 ] { }
+check-order ge-order : r1 r2 ;
+if [ mark-order r1 : test1 ] = [ mark-order r2 : test2 ] { }
+check-order eq-order : r1 r2 ;
+if [ mark-order r1 : test1 ] != [ mark-order r2 : test2 ] { }
+check-order ne-order : r1 r2 ;
+if [ mark-order r1 : test1 ] in [ mark-order r2 : test2 ] { }
+check-order in-order : r1 r2 ;
+
+if [ mark-order r1 : test1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order : r1 r2 ;
+if [ mark-order r1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order-short-circuit : r1 ;
+
+if [ mark-order r1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order : r1 r2 ;
+if [ mark-order r1 : test1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order-short-circuit : r1 ;
+
+}
+
+# Check include
+
+{
+#FIXME:
+# plain include
+# include in module
+# include returns an empty list
+# rule arguments are available inside include
+}
+
+# Check local
+
+{
+
+local v1 = a b c ;
+local v2 = f g h ;
+
+{
+ local v1 ;
+ check-equal local-no-init : $(v1) : ;
+}
+
+check-equal local-restore : $(v1) : a b c ;
+
+{
+ local v1 = d e f ;
+ check-equal local-init : $(v1) : d e f ;
+}
+
+check-equal local-restore-init : $(v1) : a b c ;
+
+{
+ local v1 v2 ;
+ check-equal local-multiple-no-init : $(v1) - $(v2) : - ;
+}
+
+check-equal local-multiple-restore : $(v1) - $(v2) : a b c - f g h ;
+
+{
+ local v1 v2 = d e f ;
+ check-equal local-multiple-init : $(v1) - $(v2) : d e f - d e f ;
+}
+
+{
+ local v1 v1 = d e f ;
+ check-equal local-duplicate : $(v1) - $(v1) : d e f - d e f ;
+}
+
+check-equal local-duplicate-restore : $(v1) : a b c ;
+
+{
+ local [ mark-order r1 : v1 ] = [ mark-order r2 : d e f ] ;
+ check-order local-order : r1 r2 ;
+}
+
+}
+
+# Check module
+
+{
+ local var1 = root-module-var ;
+ module my_module
+ {
+ var1 = module-var ;
+ rule get ( )
+ {
+ return $(var1) ;
+ }
+ local rule not_really ( ) { return nothing ; }
+ }
+
+ check-equal module-var-not-root : $(var1) : root-module-var ;
+
+ check-equal module-rulenames : [ RULENAMES my_module ] : get ;
+
+ IMPORT_MODULE my_module ;
+ check-equal module-rule-import-module : [ my_module.get ] : module-var ;
+
+ IMPORT my_module : get : : module-get ;
+ check-equal module-rule-imort : [ module-get ] : module-var ;
+
+ IMPORT my_module : get : : module-get : LOCALIZE ;
+ check-equal module-rule-imort-localize : [ module-get ] : root-module-var ;
+
+}
+
+# Check class
+{
+#FIXME:
+# ...
+}
+
+# Check on
+
+{
+
+local target1 = test-on-target1 ;
+local target2 = test-on-target2 ;
+local targets = $(target1) $(target2) ;
+local v1 v2 v3 ;
+
+VAR on $(target1) = value1 ;
+V2 on $(target2) = value2 ;
+
+check-equal on-return : [ on $(target1) return $(VAR) ] : value1 ;
+
+rule test-rule
+{
+ return $(VAR) ;
+}
+
+check-equal on-rule : [ on $(target1) test-rule ] : value1 ;
+
+check-equal on-multiple : [ on $(targets) return $(V2) ] : ;
+
+rule test-rule
+{
+ on $(target1)
+ {
+ return $(VAR) ;
+ }
+}
+
+check-equal on-block : [ test-rule ] : value1 ;
+
+# FIXME: crazy implementation artifacts:
+
+v1 on test-on-target3 = x1 ;
+on test-on-target3
+{
+ v1 on test-on-target3 += x1 ;
+ v1 = y1 ;
+ v2 on test-on-target3 += x2 ;
+ v2 = y2 ;
+ v3 = y3 ;
+}
+
+check-equal on-swap-old1 : $(v1) : x1 ;
+check-equal on-swap-old2 : [ on test-on-target3 return $(v1) ] : y1 ;
+check-equal on-swap-new1 : $(v2) : x2 ;
+check-equal on-swap-new2 : [ on test-on-target3 return $(v2) ] : y2 ;
+check-equal on-no-swap : $(v3) : y3 ;
+
+}
+
+# Check rule
+
+{
+#FIXME:
+# argument order
+# expand rule name
+}
+
+# Check rules
+
+{
+#FIXME:
+}
+
+# Check set
+
+{
+local v1 ;
+local v2 ;
+local v3 ;
+local vars = v1 v2 v3 ;
+
+v1 = x1 ;
+check-equal set-set-empty : $(v1) : x1 ;
+v2 += x2 ;
+check-equal set-append-empty : $(v2) : x2 ;
+v3 ?= x3 ;
+check-equal set-default-empty : $(v3) : x3 ;
+
+v1 = y1 ;
+check-equal set-set-non-empty : $(v1) : y1 ;
+v2 += y2 ;
+check-equal set-append-non-empty : $(v2) : x2 y2 ;
+v3 ?= y3 ;
+check-equal set-default-non-empty : $(v3) : x3 ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) = z ;
+check-equal set-set-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) += z ;
+check-equal set-append-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) ?= z ;
+check-equal set-default-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-non-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-non-empty-group : $(v1) - $(v2) - $(v3) : x1 z - x2 z - x3 z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-non-empty-group : $(v1) - $(v2) - $(v3) : x1 - x2 - x3 ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-mixed-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-mixed-group : $(v1) - $(v2) - $(v3) : x1 z - z - x3 z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-mixed-group : $(v1) - $(v2) - $(v3) : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+v1 = ;
+$(vars) = z ;
+check-equal set-set-duplicate-empty : $(v1) : z ;
+v1 = ;
+$(vars) += z ;
+check-equal set-append-duplicate-empty : $(v1) : z z ;
+v1 = ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-empty : $(v1) : z ;
+
+v1 = x1 ;
+$(vars) = z ;
+check-equal set-set-duplicate-non-empty : $(v1) : z ;
+v1 = x1 ;
+$(vars) += z ;
+check-equal set-append-duplicate-non-empty : $(v1) : x1 z z ;
+v1 = x1 ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-non-empty : $(v1) : x1 ;
+
+rule test-rule { v1 = x1 ; }
+check-equal set-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 += x1 ; }
+check-equal set-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 ?= x1 ; }
+check-equal set-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 ] = [ mark-order r2 ] ;
+check-order set-set-order : r1 r2 ;
+[ mark-order r1 ] += [ mark-order r2 ] ;
+check-order set-append-order : r1 r2 ;
+[ mark-order r1 ] ?= [ mark-order r2 ] ;
+check-order set-default-order : r1 r2 ;
+
+}
+
+# Check setcomp
+
+{
+#FIXME
+# Expand arguments
+# Don't expand name
+}
+
+# Check setexec
+
+{
+#FIXME:
+# Don't expand name
+# Evaluate bindlist
+}
+
+# Check settings ;
+
+{
+
+local target1 = test-settings-target1 ;
+local target2 = test-settings-target2 ;
+local target3 = test-settings-target3 ;
+local targets = $(target2) $(target3) ;
+
+local vars = v1 v2 v3 ;
+
+v1 on $(target1) = x1 ;
+check-equal settings-set-empty : [ on $(target1) return $(v1) ] : x1 ;
+v2 on $(target1) += x2 ;
+check-equal settings-append-empty : [ on $(target1) return $(v2) ] : x2 ;
+v3 on $(target1) ?= x3 ;
+check-equal settings-default-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+v1 on $(target1) = y1 ;
+check-equal settings-set-non-empty : [ on $(target1) return $(v1) ] : y1 ;
+v2 on $(target1) += y2 ;
+check-equal settings-append-non-empty : [ on $(target1) return $(v2) ] : x2 y2 ;
+v3 on $(target1) ?= y3 ;
+check-equal settings-default-non-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+$(vars) on setting-target2 = z ;
+check-equal settings-set-empty-group : [ on setting-target2 return $(v1) ] - [ on setting-target2 return $(v2) ] - [ on setting-target2 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target3 += z ;
+check-equal settings-append-empty-group : [ on setting-target3 return $(v1) ] - [ on setting-target3 return $(v2) ] - [ on setting-target3 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target4 ?= z ;
+check-equal settings-default-empty-group : [ on setting-target4 return $(v1) ] - [ on setting-target4 return $(v2) ] - [ on setting-target4 return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 z - x2 z - x3 z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 - x2 - x3 ;
+
+v1 on setting-target5 = x1 ;
+v3 on setting-target5 = x3 ;
+$(vars) on setting-target5 = z ;
+check-equal settings-set-mixed-group : [ on setting-target5 return $(v1) ] - [ on setting-target5 return $(v2) ] - [ on setting-target5 return $(v3) ] : z - z - z ;
+
+v1 on setting-target6 = x1 ;
+v3 on setting-target6 = x3 ;
+$(vars) on setting-target6 += z ;
+check-equal settings-append-mixed-group : [ on setting-target6 return $(v1) ] - [ on setting-target6 return $(v2) ] - [ on setting-target6 return $(v3) ] : x1 z - z - x3 z ;
+
+v1 on setting-target7 = x1 ;
+v3 on setting-target7 = x3 ;
+$(vars) on setting-target7 ?= z ;
+check-equal settings-default-mixed-group : [ on setting-target7 return $(v1) ] - [ on setting-target7 return $(v2) ] - [ on setting-target7 return $(v3) ] : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+$(vars) on setting-target8 = z ;
+check-equal settings-set-duplicate-empty : [ on setting-target8 return $(v1) ] : z ;
+$(vars) on setting-target9 += z ;
+check-equal settings-append-duplicate-empty : [ on setting-target9 return $(v1) ] : z z ;
+$(vars) on setting-target10 ?= z ;
+check-equal settings-default-duplicate-empty : [ on setting-target10 return $(v1) ] : z ;
+
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-duplicate-non-empty : [ on $(target1) return $(v1) ] : z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 z z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 ;
+
+v1 on $(target1) = ;
+v1 on $(target1) ?= z ;
+check-equal settings-default-set-but-empty : [ on $(target1) return $(v1) ] : ;
+
+v1 on $(targets) = multi ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi - multi ;
+v2 on $(targets) += multi ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi - multi ;
+v3 on $(targets) ?= multi ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+v1 on $(targets) = multi2 ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi2 - multi2 ;
+v2 on $(targets) += multi2 ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi multi2 - multi multi2 ;
+v3 on $(targets) ?= multi2 ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+rule test-rule { v1 on $(target1) = x1 ; }
+check-equal settings-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) += x1 ; }
+check-equal settings-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) ?= x1 ; }
+check-equal settings-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] = [ mark-order r2 : value ] ;
+check-order settings-set-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] += [ mark-order r2 : value ] ;
+check-order settings-append-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] ?= [ mark-order r2 : value ] ;
+check-order settings-default-order : r1 r2 r3 ;
+
+}
+
+# Check switch
+
+{
+
+local pattern = * ;
+
+switch value
+{
+ case * : mark-order r1 ;
+}
+
+check-order switch-match-any : r1 ;
+
+switch value
+{
+ case v2 : mark-order r1 ;
+}
+
+check-order switch-no-match : ;
+
+switch value
+{
+ case $(pattern) : mark-order r1 ;
+}
+
+check-order switch-no-expand : ;
+
+switch value
+{
+ case value : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-match-several : r1 ;
+
+rule test-rule ( value )
+{
+ switch $(value)
+ {
+ case value : return 1 ;
+ }
+}
+
+check-equal switch-result-match : [ test-rule value ] : 1 ;
+check-equal switch-result-match : [ test-rule v1 ] : ;
+
+switch $()
+{
+ case "" : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-empty : r1 ;
+
+local values = v1 v2 v3 ;
+switch $(values)
+{
+ case v1 : mark-order r1 ;
+ case v2 : mark-order r2 ;
+ case v3 : mark-order r3 ;
+}
+
+check-order switch-multiple : r1 ;
+
+# Test glob matching
+
+switch value { case * : mark-order r1 ; }
+check-order switch-glob-star : r1 ;
+
+switch value { case va*e : mark-order r1 ; }
+check-order switch-glob-star-1 : r1 ;
+
+switch value { case *a* : mark-order r1 ; }
+check-order switch-glob-star-2 : r1 ;
+
+switch value { case *a*ue* : mark-order r1 ; }
+check-order switch-glob-star-3 : r1 ;
+
+switch value { case *[eaiou]*ue : mark-order r1 ; }
+check-order switch-glob-group : r1 ;
+
+switch value { case *[eaiou]ue : mark-order r1 ; }
+check-order switch-glob-group-fail : ;
+
+switch value { case ?a?ue : mark-order r1 ; }
+check-order switch-glob-any : r1 ;
+
+switch value { case ?lue : mark-order r1 ; }
+check-order switch-glob-any-fail : ;
+
+}
+
+# Test while
+
+{
+
+local value = 1 2 3 ;
+
+while $(value)
+{
+ mark-order r$(value[1]) ;
+ value = $(value[2-]) ;
+}
+
+check-order while-exec : r1 r2 r3 ;
+
+rule test-rule
+{
+ local value = 1 2 3 ;
+ while $(value)
+ {
+ value = $(value[2-]) ;
+ return x ;
+ }
+}
+
+check-equal while-result : [ test-rule ] : x ;
+
+rule test-rule
+{
+ local value = 1 2 ;
+ while $(value)
+ {
+ value = $(value[2-]) ;
+ local inner = $(value) ;
+ while $(inner)
+ {
+ inner = $(inner[2-]) ;
+ return x ;
+ }
+ }
+}
+
+check-equal while-result-2 : [ test-rule ] : ;
+
+}
+
+#
+# test CALLER_MODULE and backtrace
+#
+
+{
+ local base = [ BACKTRACE ] ;
+ base = $(base[2]) ;
+ rule backtrace ( )
+ {
+ local bt = [ BACKTRACE ] ;
+ check-equal backtrace-1-file : $(bt) :
+ test.jam [ CALC $(base) + 4 ] "" backtrace
+ test.jam [ CALC $(base) + 28 ] module2. module2.f
+ test.jam [ CALC $(base) + 19 ] module1. module1.f
+ test.jam [ CALC $(base) + 32 ] "" "module scope"
+ ;
+ }
+ module module1
+ {
+ IMPORT_MODULE module2 : module1 ;
+ rule f ( )
+ {
+ local m = [ CALLER_MODULE ] ;
+ check-equal caller-module-root : $(m) ;
+ module2.f ;
+ }
+ }
+ module module2
+ {
+ rule f ( )
+ {
+ local m = [ CALLER_MODULE ] ;
+ check-equal caller-module : module1 : $(m) ;
+ backtrace ;
+ }
+ }
+ IMPORT_MODULE module1 ;
+ module1.f ;
+}
+
+
+# Test NORMALIZE_PATH
+
+{
+check-equal normalize-path : "." : [ NORMALIZE_PATH ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH ".." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "//" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "//\\\\//\\\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\///.///\\\\\\" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "./././././." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./././././." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////././." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////./././" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "///foo/\\\\/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\\\foo\\//\\.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/./.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/././././.." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././.././././baz/./././.." ] ;
+check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././.././././baz/./././.." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././////.././././baz/./././.." ] ;
+check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././////.././././baz/./././.." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH "./.." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH "././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./.././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././.././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "..//\\\\\\//.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../..\\\\/\\\\" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/../bar/../baz/.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////..////bar////.//////.////../baz/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo/../bar/../baz/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo////..////bar////.//////.////../baz/.." ] ;
+
+# Invalid rooted paths with leading dotdots.
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../" ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "//\\\\//\\\\/.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "\\\\//\\\\//\\.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/foo/bar/../baz/../../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../for/././../././bar/././../././.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../foo/bar" ] ;
+
+}
+
+# Test W32_GETREGNAMES
+
+{
+
+if $(NT)
+{
+ local sound = "Beep" "ExtendedSounds" ;
+ local r1 = [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ;
+ check-equal w32_getregnames : $(sound:L) : $(r1:L) ;
+ local r2 = [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ;
+ check-equal w32_getregnames : $(sound:L) : $(r2:L) ;
+
+ local CurrentControlSet = "Control" "Enum" "Hardware Profiles" "Services" ;
+ local r3 = [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" : subkeys ] ;
+ check-equal w32_getregnames : $(CurrentControlSet:L) : $(r3:L) ;
+ local r4 = [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ;
+ check-equal w32_getregnames : $(CurrentControlSet:L) : $(r4:L) ;
+}
+
+}
+
+# Test SHELL
+
+{
+
+local c = "echo value" ;
+
+check-equal shell : "value\n" : [ SHELL $(c) ] ;
+check-equal shell : "" : [ SHELL $(c) : no-output ] ;
+check-equal shell : "value\n" 0 : [ SHELL $(c) : exit-status ] ;
+check-equal shell : "" 0 : [ SHELL $(c) : no-output : exit-status ] ;
+check-equal command : "value\n" : [ COMMAND $(c) ] ;
+check-equal command : "" : [ COMMAND $(c) : no-output ] ;
+check-equal command : "value\n" 0 : [ COMMAND $(c) : exit-status ] ;
+check-equal command : "" 0 : [ COMMAND $(c) : no-output : exit-status ] ;
+
+}
+
+# Test SUBST
+
+{
+
+# Check that unmatched subst returns an empty list
+check-equal subst-nomatch : [ SUBST "abc" "d+" x ] : ;
+
+# Check that a matched subst works
+check-equal subst-match : [ SUBST "ddd" "d+" x ] : x ;
+
+# Check that we can get multiple substitutions from a single invocation
+check-equal subst-multiple : [ SUBST "x/y/z" "([^/]*)/([^/]*).*" "\\1" $2 "\\1-\\2" ] : x y x-y ;
+
+}
+
+# Test summary
+
+if $(failed) = 0
+{
+ status = 0 ;
+}
+else
+{
+ status = 1 ;
+}
+
+EXIT $(passed) passed $(failed) failed : $(status) ;
diff --git a/tools/build/v2/test/core_action_status.py b/tools/build/v2/test/core_action_status.py
new file mode 100755
index 0000000000..75dbdf5391
--- /dev/null
+++ b/tools/build/v2/test/core_action_status.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("file.jam", """
+ actions quietly .a. { $(ACTION) }
+
+ rule .a.
+ {
+ DEPENDS $(<) : $(>) ;
+ }
+
+ NOTFILE subtest ;
+ .a. subtest_a : subtest ;
+ DEPENDS all : subtest_a ;
+""")
+
+t.run_build_system("-ffile.jam -sACTION=invalid", status=1)
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/actions_quietly.jam b/tools/build/v2/test/core_actions_quietly.py
index e7b9ad86cb..e8d5d43413 100644..100755
--- a/tools/build/v2/test/engine/actions_quietly.jam
+++ b/tools/build/v2/test/core_actions_quietly.py
@@ -1,12 +1,34 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing \"actions quietly\"... ;
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- assert "...found 4 targets...
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("file.jam", """
+ actions quietly .a.
+ {
+echo [$(<:B)] 0
+echo [$(<:B)] 1
+echo [$(<:B)] 2
+ }
+
+ rule .a.
+ {
+ DEPENDS $(<) : $(>) ;
+ }
+
+ NOTFILE subtest ;
+ .a. subtest_a : subtest ;
+ .a. subtest_b : subtest ;
+ DEPENDS all : subtest_a subtest_b ;
+""")
+
+t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
...updating 2 targets...
.a. subtest_a
@@ -27,29 +49,11 @@ echo [subtest_b] 2
[subtest_b] 1
[subtest_b] 2
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f actions_quietly.jam -sBJAM_SUBTEST=1 -d2" ] ;
+""")
- assert "...found 4 targets...
+t.run_build_system("-ffile.jam -d1", stdout="""...found 4 targets...
...updating 2 targets...
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f actions_quietly.jam -sBJAM_SUBTEST=1" ] ;
-}
-else
-{
- actions quietly .a.
- {
-echo [$(<:B)] 0
-echo [$(<:B)] 1
-echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- DEPENDS all : subtest_a subtest_b ;
-}
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_arguments.py b/tools/build/v2/test/core_arguments.py
new file mode 100755
index 0000000000..5a1bc9b655
--- /dev/null
+++ b/tools/build/v2/test/core_arguments.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+# Copyright 2001 Dave Abrahams
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("echo_args.jam", """
+rule echo_args ( a b ? c ? : d + : e * )
+{
+ ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ;
+}
+
+rule echo_varargs ( a b ? c ? : d + : e * : * )
+{
+ ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e)
+ ": rest= "$(4[1]) $(4[2])
+ ": "$(5[1]) $(5[2])
+ ": "$(6[1]) $(6[2])
+ ": "$(7[1]) $(7[2])
+ ": "$(8[1]) $(8[2])
+ ": "$(9[1]) $(9[2]) ;
+}
+""")
+
+t.write("file.jam", "include echo_args.jam ; echo_args ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("* missing argument a");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 2 : 3 : 4 : 5 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("* extra argument 5");
+
+t.write("file.jam", "include echo_args.jam ; echo_args a b c1 c2 : d ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("* extra argument c2");
+
+# Check modifier '?'
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 2 3 : 4 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= 2 c= 3 : d= 4 : e=");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 2 : 3 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= 2 c= : d= 3 : e=");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e=");
+
+# Check modifier '+'
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("* missing argument d");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 3 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 3 : e=");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 3 4 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 3 4 : e=");
+
+# Check modifier '*'
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 4 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4");
+
+t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 4 5 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5");
+
+#
+# Check varargs
+#
+
+t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5");
+
+t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6");
+
+t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7");
+
+t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 : 8 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8");
+
+t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 : 8 : 9 ;")
+t.run_build_system("-ffile.jam", status=1)
+t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9");
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_at_file.py b/tools/build/v2/test/core_at_file.py
new file mode 100755
index 0000000000..71f1bbcebe
--- /dev/null
+++ b/tools/build/v2/test/core_at_file.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+EXIT file: "@(o$(name) .txt:E= test -D$(contents))" : 0 ;
+""")
+
+t.run_build_system("-ffile.jam")
+t.expect_output_line("file: on1 on2 .txt");
+t.expect_addition("on1 on2 .txt")
+t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+actions run {
+echo file: "@(o$(name) .txt:E= test -D$(contents))"
+}
+
+run all ;
+
+""")
+
+t.run_build_system("-ffile.jam -d2")
+t.expect_output_line('echo file: "on1 on2 .txt"');
+t.expect_addition("on1 on2 .txt")
+t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+file = "@($(STDOUT):E= test -D$(contents)\n)" ;
+
+actions run {
+$(file)
+}
+
+run all ;
+""")
+
+t.run_build_system("-ffile.jam -d1")
+t.expect_output_line(" test -DM1 -DM2")
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+actions run {
+@($(STDOUT):E= test -D$(contents)\n)
+}
+
+run all ;
+
+""")
+
+t.run_build_system("-ffile.jam -d1")
+t.expect_output_line(" test -DM1 -DM2")
+
+t.cleanup()
diff --git a/tools/build/v2/test/check-bindrule.jam b/tools/build/v2/test/core_bindrule.py
index f8eb986e39..d5aaa7fc53 100644..100755
--- a/tools/build/v2/test/check-bindrule.jam
+++ b/tools/build/v2/test/core_bindrule.py
@@ -1,8 +1,18 @@
+#!/usr/bin/python
+
# Copyright 2001 Dave Abrahams
+# Copyright 2011 Steven Watanabe
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-# This rule establishes a dependency, with no special build actions
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("subdir1/file-to-bind", "# This file intentionally left blank")
+
+t.write("file.jam", """
rule do-nothing ( target : source )
{
DEPENDS $(target) : $(source) ;
@@ -27,3 +37,11 @@ rule bind-rule ( target : path )
}
DEPENDS all : fake-target ;
+""")
+
+t.run_build_system("-ffile.jam", stdout="""found: all at all
+found: file-to-bind at subdir1%sfile-to-bind
+...found 3 targets...
+""" % os.sep)
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_import_module.py b/tools/build/v2/test/core_import_module.py
index fab209e4cb..2ab5942415 100644
--- a/tools/build/v2/test/core_import_module.py
+++ b/tools/build/v2/test/core_import_module.py
@@ -15,6 +15,11 @@ module a
{
ECHO R1 ;
}
+
+ local rule l1 ( )
+ {
+ ECHO A.L1 ;
+ }
}
module a2
{
@@ -25,6 +30,11 @@ module a2
}
IMPORT a2 : r2 : : a2.r2 ;
+rule a.l1 ( )
+{
+ ECHO L1 ;
+}
+
module b
{
IMPORT_MODULE a : b ;
@@ -34,6 +44,11 @@ module b
a.r1 ;
# Call rule in global scope
a2.r2 ;
+ # Call rule in global scope. Doesn't find local rule
+ a.l1 ;
+ # Make l1 visible
+ EXPORT a : l1 ;
+ a.l1 ;
}
}
@@ -57,6 +72,8 @@ do-nothing all ;
t.run_build_system("-fcode", stdout="""R1
R2
+L1
+A.L1
CTEST
""")
diff --git a/tools/build/v2/test/project-test1/dir2/jamfile.jam b/tools/build/v2/test/core_language.py
index 8d1c48b65b..42b4366894 100644..100755
--- a/tools/build/v2/test/project-test1/dir2/jamfile.jam
+++ b/tools/build/v2/test/core_language.py
@@ -1,9 +1,14 @@
-# Copyright 2004 Rene Rivera
+#!/usr/bin/python
+
# Copyright 2002, 2003 Vladimir Prus
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.set_tree("core-language")
+t.run_build_system(extra_args="-ftest.jam")
-project /cool-library
- : requirements <include>/home/ghost/build/boost-cvs
- ;
+t.cleanup()
diff --git a/tools/build/v2/test/test_nt_line_length.jam b/tools/build/v2/test/core_nt_line_length.py
index bc003964e3..809c5e1ec5 100644..100755
--- a/tools/build/v2/test/test_nt_line_length.jam
+++ b/tools/build/v2/test/core_nt_line_length.py
@@ -1,11 +1,16 @@
+#!/usr/bin/python
+
# Copyright 2001 Dave Abrahams
+# Copyright 2011 Steven Watanabe
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-# Test that the patch which allows long command-lines in actions on NT is
-# working. For reasons of backward-compatibility, this patch requires that the
-# action fits on a single command-line, and that the JAMSHELL variable on the
-# target being built is set to "%".
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("file.jam", """
if $(NT)
{
#
@@ -37,3 +42,11 @@ if $(NT)
do_echo line_length_test ;
}
+else
+{
+ NOCARE all ;
+}
+""")
+t.run_build_system("-ffile.jam")
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/option_d2.jam b/tools/build/v2/test/core_option_d2.py
index 6dee8f47e7..0784954020 100644..100755
--- a/tools/build/v2/test/engine/option_d2.jam
+++ b/tools/build/v2/test/core_option_d2.py
@@ -1,12 +1,39 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -d2 option... ;
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- assert "...found 4 targets...
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+timeout /T %1 /NOBREAK >nul
+""")
+
+t.write("file.jam", """
+ actions .a.
+ {
+echo [$(<:B)] 0
+echo [$(<:B)] 1
+echo [$(<:B)] 2
+ }
+
+ rule .a.
+ {
+ DEPENDS $(<) : $(>) ;
+ }
+
+ NOTFILE subtest ;
+ .a. subtest_a : subtest ;
+ .a. subtest_b : subtest ;
+ DEPENDS all : subtest_a subtest_b ;
+""")
+
+t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
...updating 2 targets...
.a. subtest_a
@@ -27,24 +54,6 @@ echo [subtest_b] 2
[subtest_b] 1
[subtest_b] 2
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_d2.jam -sBJAM_SUBTEST=1 -d2" ] ;
-}
-else
-{
- actions .a.
- {
-echo [$(<:B)] 0
-echo [$(<:B)] 1
-echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- DEPENDS all : subtest_a subtest_b ;
-}
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_option_l.py b/tools/build/v2/test/core_option_l.py
new file mode 100755
index 0000000000..e05e9a9517
--- /dev/null
+++ b/tools/build/v2/test/core_option_l.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@REM timeout /T %1 /NOBREAK >nul
+ping 127.0.0.1 -n 2 -w 1000 >nul
+ping 127.0.0.1 -n %1 -w 1000 >nul
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+if $(NT)
+{
+ SLEEP = @call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+actions .a. {
+echo 001
+$(SLEEP) 4
+echo 002
+}
+
+.a. sleeper ;
+
+DEPENDS all : sleeper ;
+""")
+
+t.run_build_system("-ffile.jam -d1 -l2", status=1)
+
+t.expect_output_line("2 second time limit exceeded")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_option_n.py b/tools/build/v2/test/core_option_n.py
new file mode 100755
index 0000000000..3b91d8e632
--- /dev/null
+++ b/tools/build/v2/test/core_option_n.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("file.jam", """
+ actions .a.
+ {
+echo [$(<:B)] 0
+echo [$(<:B)] 1
+echo [$(<:B)] 2
+ }
+
+ rule .a.
+ {
+ DEPENDS $(<) : $(>) ;
+ }
+
+ NOTFILE subtest ;
+ .a. subtest_a : subtest ;
+ .a. subtest_b : subtest ;
+ FAIL_EXPECTED subtest_b ;
+ DEPENDS all : subtest_a subtest_b ;
+""")
+
+t.run_build_system("-ffile.jam -n", stdout="""...found 4 targets...
+...updating 2 targets...
+.a. subtest_a
+
+echo [subtest_a] 0
+echo [subtest_a] 1
+echo [subtest_a] 2
+
+.a. subtest_b
+
+echo [subtest_b] 0
+echo [subtest_b] 1
+echo [subtest_b] 2
+
+...updated 2 targets...
+""")
+
+t.expect_nothing_more()
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/parallel_actions.jam b/tools/build/v2/test/core_parallel_actions.py
index adcd1ad855..dedf9b1183 100644..100755
--- a/tools/build/v2/test/engine/parallel_actions.jam
+++ b/tools/build/v2/test/core_parallel_actions.py
@@ -1,60 +1,34 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of actions... ;
+# Copyright 2006 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- assert "...found 12 targets...
-...updating 8 targets...
-sleeper 1.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 2.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 3.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 4.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 1.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 2.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 3.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 4.b
-[.b] 0
-[.b] 1
-[.b] 2
-...updated 8 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_actions.jam -sBJAM_SUBTEST=1 -j4" ] ;
-}
-else
-{
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@REM timeout /T %1 /NOBREAK >nul
+ping 127.0.0.1 -n 2 -w 1000 >nul
+ping 127.0.0.1 -n %1 -w 1000 >nul
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
if $(NT)
{
actions sleeper
{
echo [$(<:S)] 0
-sleep 1
+@call sleep.bat 1
echo [$(<:S)] 1
-sleep 1
+@call sleep.bat 1
echo [$(<:S)] 2
-sleep $(<:B)
+@call sleep.bat $(<:B)
}
}
else
@@ -88,4 +62,43 @@ sleep $(<:B)
sleeper 4.b : choke ;
DEPENDS bottom : 1.b 2.b 3.b 4.b ;
DEPENDS all : bottom ;
-}
+""")
+
+t.run_build_system("-ffile.jam -j4", stdout="""...found 12 targets...
+...updating 8 targets...
+sleeper 1.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 2.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 3.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 4.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 1.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 2.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 3.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 4.b
+[.b] 0
+[.b] 1
+[.b] 2
+...updated 8 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_parallel_multifile_actions_1.py b/tools/build/v2/test/core_parallel_multifile_actions_1.py
new file mode 100755
index 0000000000..9d995dbca4
--- /dev/null
+++ b/tools/build/v2/test/core_parallel_multifile_actions_1.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+
+# Copyright 2007 Rene Rivera.
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@REM timeout /T %1 /NOBREAK >nul
+ping 127.0.0.1 -n 2 -w 1000 >nul
+ping 127.0.0.1 -n %1 -w 1000 >nul
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+ if $(NT)
+ {
+ SLEEP = @call sleep.bat ;
+ }
+ else
+ {
+ SLEEP = sleep ;
+ }
+
+ actions .gen. {
+echo 001
+$(SLEEP) 4
+echo 002
+}
+ rule .use.1 { DEPENDS $(<) : $(>) ; }
+ actions .use.1 {
+echo 003
+}
+ rule .use.2 { DEPENDS $(<) : $(>) ; }
+ actions .use.2 {
+$(SLEEP) 1
+echo 004
+}
+
+ .gen. g1.generated g2.generated ;
+ .use.1 u1.user : g1.generated ;
+ .use.2 u2.user : g2.generated ;
+
+ NOTFILE root ;
+ DEPENDS g1.generated g2.generated : root ;
+ DEPENDS all : u1.user u2.user ;
+""")
+
+t.run_build_system("-ffile.jam -j2", stdout="""...found 6 targets...
+...updating 4 targets...
+.gen. g1.generated
+001
+002
+.use.1 u1.user
+003
+.use.2 u2.user
+004
+...updated 4 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/parallel_multifile_actions_2.jam b/tools/build/v2/test/core_parallel_multifile_actions_2.py
index a85cf63fdb..aae0fe26e6 100644..100755
--- a/tools/build/v2/test/engine/parallel_multifile_actions_2.jam
+++ b/tools/build/v2/test/core_parallel_multifile_actions_2.py
@@ -1,6 +1,9 @@
+#!/usr/bin/python
+
# Copyright 2008 Jurko Gospodnetic, Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
# Added to guard against a bug causing targets to be used before they
# themselves have finished building. This used to happen for targets built by a
@@ -14,24 +17,33 @@
# while the action was still running, target A was already reporting as being
# built causing other targets depending on target A to be built prematurely.
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of multi-file actions - 2... ;
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@REM timeout /T %1 /NOBREAK >nul
+ping 127.0.0.1 -n 2 -w 1000 >nul
+ping 127.0.0.1 -n %1 -w 1000 >nul
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+ if $(NT)
+ {
+ SLEEP = @call sleep.bat ;
+ }
+ else
+ {
+ SLEEP = sleep ;
+ }
- assert "...found 4 targets...
-...updating 3 targets...
-link dll
-001 - linked
-install installed_dll
-002 - installed
-...updated 3 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_multifile_actions_2.jam -sBJAM_SUBTEST=1 -j2" ] ;
-}
-else
-{
actions link
{
- sleep 1
+ $(SLEEP) 1
echo 001 - linked
}
@@ -46,4 +58,15 @@ else
DEPENDS installed_dll : dll ;
DEPENDS all : lib installed_dll ;
-}
+""")
+
+t.run_build_system("-ffile.jam -j2", stdout="""...found 4 targets...
+...updating 3 targets...
+link dll
+001 - linked
+install installed_dll
+002 - installed
+...updated 3 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_update_now.py b/tools/build/v2/test/core_update_now.py
new file mode 100755
index 0000000000..d31a8c5607
--- /dev/null
+++ b/tools/build/v2/test/core_update_now.py
@@ -0,0 +1,198 @@
+#!/usr/bin/python
+
+# Copyright 2011 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import BoostBuild
+import os
+
+def basic():
+ # Basic test
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+def ignore_minus_n():
+ # ignore-minus-n
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+
+ echo updating target1
+
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+def failed_target():
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions fail
+{
+ exit 1
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+fail target1 ;
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target2 ;
+do-print target2 ;
+DEPENDS target2 : target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 target2 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+...failed updating 1 target...
+...found 2 targets...
+...updating 1 target...
+do-print target2
+
+ echo updating target2
+
+...updated 1 target...
+""")
+
+ t.cleanup()
+
+def missing_target():
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target2 ;
+do-print target2 ;
+DEPENDS target2 : target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 target2 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", status=1, stdout="""don't know how to make target1
+...found 1 target...
+...can't find 1 target...
+...found 2 targets...
+...can't make 1 target...
+""")
+
+ t.cleanup()
+
+# Make sure that if we call UPDATE_NOW with ignore-minus-n,
+# the target gets updated exactly once regardless of previous
+# calls to UPDATE_NOW with -n in effect.
+
+def build_once():
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 ;
+UPDATE_NOW target1 : : ignore-minus-n ;
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+
+ echo updating target1
+
+...updated 1 target...
+do-print target1
+
+ echo updating target1
+
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+basic()
+ignore_minus_n()
+failed_target()
+missing_target()
+build_once()
diff --git a/tools/build/v2/test/direct-request-test/a.cpp b/tools/build/v2/test/direct-request-test/a.cpp
deleted file mode 100644
index cb97ea0c3e..0000000000
--- a/tools/build/v2/test/direct-request-test/a.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2003 Vladimir Prus
-//
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// http://www.boost.org
-//
-
-void
-# ifdef _WIN32
-__declspec(dllimport)
-# endif
-foo();
-
-int main()
-{
- foo();
-}
diff --git a/tools/build/v2/test/direct-request-test/b.cpp b/tools/build/v2/test/direct-request-test/b.cpp
deleted file mode 100644
index 22dc6bb5d8..0000000000
--- a/tools/build/v2/test/direct-request-test/b.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2003 Vladimir Prus
-//
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// http://www.boost.org
-//
-
-// This file will declare 'foo' is 'MACROS' is defined.
-
-#ifdef MACROS
-void
-# ifdef _WIN32
-__declspec(dllexport)
-# endif
-foo() {}
-#endif
-
-# ifdef _WIN32
-int __declspec(dllexport) force_implib_creation;
-# endif
diff --git a/tools/build/v2/test/direct-request-test/b_inverse.cpp b/tools/build/v2/test/direct-request-test/b_inverse.cpp
deleted file mode 100644
index 5068f6118a..0000000000
--- a/tools/build/v2/test/direct-request-test/b_inverse.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2003 Vladimir Prus
-//
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// http://www.boost.org
-//
-
-// This file will declare 'foo' is 'MACROS' is NOT defined.
-
-#ifndef MACROS
-void
-# ifdef _WIN32
-__declspec(dllexport)
-# endif
-foo() {}
-#endif
-
-# ifdef _WIN32
-int __declspec(dllexport) force_implib_creation;
-# endif
diff --git a/tools/build/v2/test/direct-request-test/jamfile.jam b/tools/build/v2/test/direct-request-test/jamfile.jam
deleted file mode 100644
index f57874d3f0..0000000000
--- a/tools/build/v2/test/direct-request-test/jamfile.jam
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-# This will link correctly only if symbol MACROS is defined when compiling
-# b.cpp. However, this is only possible if that symbol is requested
-# on command line and b.cpp is compiled with directly requested
-# properties.
-
-exe a : a.cpp b ;
-
-lib b : b.cpp ;
diff --git a/tools/build/v2/test/direct-request-test/jamfile2.jam b/tools/build/v2/test/direct-request-test/jamfile2.jam
deleted file mode 100644
index bc7e1bc74b..0000000000
--- a/tools/build/v2/test/direct-request-test/jamfile2.jam
+++ /dev/null
@@ -1,9 +0,0 @@
-
-# This will link correctly only if symbol MACROS is not defined when
-# compiling b.cpp. This tests if direct build request
-# 'release <define>MACROS' to 'b' does not add 'MACROS' when 'b'
-# is compiled with 'debug' -- the version needed by 'a'.
-
-exe a : a.cpp b : <variant>debug ;
-
-lib b : b.cpp ; \ No newline at end of file
diff --git a/tools/build/v2/test/direct-request-test/jamroot.jam b/tools/build/v2/test/direct-request-test/jamroot.jam
deleted file mode 100644
index 845aca8545..0000000000
--- a/tools/build/v2/test/direct-request-test/jamroot.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-import gcc ;
diff --git a/tools/build/v2/test/direct_request_test.py b/tools/build/v2/test/direct_request_test.py
index 000d15b64d..32121f1d75 100644
--- a/tools/build/v2/test/direct_request_test.py
+++ b/tools/build/v2/test/direct_request_test.py
@@ -4,9 +4,42 @@ import BoostBuild
t = BoostBuild.Tester()
-
# First check some startup.
-t.set_tree("direct-request-test")
+
+t.write("jamroot.jam", "")
+
+t.write("jamfile.jam", """
+exe a : a.cpp b ;
+lib b : b.cpp ;
+""")
+
+t.write("a.cpp", """
+void
+# ifdef _WIN32
+__declspec(dllimport)
+# endif
+foo();
+
+int main()
+{
+ foo();
+}
+""")
+
+t.write("b.cpp", """
+#ifdef MACROS
+void
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+foo() {}
+#endif
+
+# ifdef _WIN32
+int __declspec(dllexport) force_implib_creation;
+# endif
+""")
+
t.run_build_system(extra_args="define=MACROS")
t.expect_addition("bin/$toolset/debug/"
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
@@ -19,11 +52,11 @@ t.expect_addition("bin/$toolset/debug/"
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
-# When building release version, the 'define' should not apply: we will have
-# direct build request 'release <define>MACROS' and a real build property
-# 'debug'.
-t.copy("jamfile2.jam", "jamfile.jam")
-t.copy("b_inverse.cpp", "b.cpp")
+# When building release version, the 'define' still applies.
+t.write("jamfile.jam", """
+exe a : a.cpp b : <variant>debug ;
+lib b : b.cpp ;
+""")
t.rm("bin")
t.run_build_system(extra_args="release define=MACROS")
diff --git a/tools/build/v2/test/echo_args.jam b/tools/build/v2/test/echo_args.jam
deleted file mode 100644
index 0f6956e462..0000000000
--- a/tools/build/v2/test/echo_args.jam
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-rule echo_args ( a b ? c ? : d + : e * )
-{
- ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ;
-}
-
-rule echo_varargs ( a b ? c ? : d + : e * : * )
-{
- ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e)
- ": rest= "$(4[1]) $(4[2])
- ": "$(5[1]) $(5[2])
- ": "$(6[1]) $(6[2])
- ": "$(7[1]) $(7[2])
- ": "$(8[1]) $(8[2])
- ": "$(9[1]) $(9[2]) ;
-}
-
diff --git a/tools/build/v2/test/empty.jam b/tools/build/v2/test/empty.jam
deleted file mode 100644
index c6220580ca..0000000000
--- a/tools/build/v2/test/empty.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# This file is empty; it just suppresses warnings
diff --git a/tools/build/v2/test/engine/README.txt b/tools/build/v2/test/engine/README.txt
deleted file mode 100644
index c38701fb8a..0000000000
--- a/tools/build/v2/test/engine/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-This directory contains tests for the update engine of
-Boost.Build. They presently are not integrated with
-the Python based test system and must be run by
-hand.
diff --git a/tools/build/v2/test/engine/action_status.jam b/tools/build/v2/test/engine/action_status.jam
deleted file mode 100644
index ee1c6c382a..0000000000
--- a/tools/build/v2/test/engine/action_status.jam
+++ /dev/null
@@ -1,28 +0,0 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing \"actions status results\"... ;
-
- assert "" 0 : (==) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1" : exit-status : no-output ] ;
- if $(NT)
- {
- assert "" 0 : (==) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1 \"-sACTION=;\"" : exit-status : no-output ] ;
- }
- assert "" 0 : (!=) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1 -sACTION=invalid" : exit-status : no-output ] ;
-}
-else
-{
- actions quietly .a. { $(ACTION) }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- DEPENDS all : subtest_a ;
-}
diff --git a/tools/build/v2/test/engine/builtin_normalize_path.jam b/tools/build/v2/test/engine/builtin_normalize_path.jam
deleted file mode 100644
index 76e0a9ddb0..0000000000
--- a/tools/build/v2/test/engine/builtin_normalize_path.jam
+++ /dev/null
@@ -1,60 +0,0 @@
-#~ Copyright 2008 Jurko Gospodnetic.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO --- Testing NORMALIZE_PATH builtin... ;
-
-assert "." : (==) : [ NORMALIZE_PATH ] ;
-assert "." : (==) : [ NORMALIZE_PATH "" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH ".." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "//" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "//\\\\//\\\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/./" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\///.///\\\\\\" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "./././././." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/./././././." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////././." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////./././" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo////.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "///foo/\\\\/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\\\foo\\//\\.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/./.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/././././.." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/./././bar/./././.././././baz/./././.." ] ;
-assert "/foo" : (==) : [ NORMALIZE_PATH "/foo/./././bar/./././.././././baz/./././.." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/./././bar/./././////.././././baz/./././.." ] ;
-assert "/foo" : (==) : [ NORMALIZE_PATH "/foo/./././bar/./././////.././././baz/./././.." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH "./.." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH "././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "./../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "././././../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "./.././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "././././.././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "..//\\\\\\//.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "../..\\\\/\\\\" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/../bar/../baz/.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo////..////bar////.//////.////../baz/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/foo/../bar/../baz/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/foo////..////bar////.//////.////../baz/.." ] ;
-
-# Invalid rooted paths with leading dotdots.
-assert : (==) : [ NORMALIZE_PATH "/.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../" ] ;
-assert : (==) : [ NORMALIZE_PATH "//\\\\//\\\\/.." ] ;
-assert : (==) : [ NORMALIZE_PATH "\\\\//\\\\//\\.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/foo/bar/../baz/../../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../for/././../././bar/././../././.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../foo/bar" ] ;
diff --git a/tools/build/v2/test/engine/builtin_shell.jam b/tools/build/v2/test/engine/builtin_shell.jam
deleted file mode 100644
index 13d6245e32..0000000000
--- a/tools/build/v2/test/engine/builtin_shell.jam
+++ /dev/null
@@ -1,31 +0,0 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# TODO: Here we should test for the Windows popen() command unquoting bug but
-# that test will have to wait until a better testing framework is implemented.
-# To reproduce the bug try executing any command with its first parameter quoted
-# and containing spaces and having at least one other quote in the command
-# string.
-#
-# For example:
-#
-# "\Long folder name\aaa.exe" --name="Jurko" --no-surname
-#
-# would get its outermost quotes stripped and would be executed as:
-#
-# \Long folder name\aaa.exe" --name="Jurko --no-surname
-
-ECHO --- Testing SHELL builtin... ;
-
-local c = "date" ;
-if $(NT) { c = "PATH" ; }
-
-assert "" : (!=) : [ SHELL $(c) ] ;
-assert "" : (==) : [ SHELL $(c) : no-output ] ;
-assert "" 0 : (!=) : [ SHELL $(c) : exit-status ] ;
-assert "" 0 : (==) : [ SHELL $(c) : no-output : exit-status ] ;
-assert "" : (!=) : [ COMMAND $(c) ] ;
-assert "" : (==) : [ COMMAND $(c) : no-output ] ;
-assert "" 0 : (!=) : [ COMMAND $(c) : exit-status ] ;
-assert "" 0 : (==) : [ COMMAND $(c) : no-output : exit-status ] ;
diff --git a/tools/build/v2/test/engine/builtin_w32_getregnames.jam b/tools/build/v2/test/engine/builtin_w32_getregnames.jam
deleted file mode 100644
index 1082f4ad72..0000000000
--- a/tools/build/v2/test/engine/builtin_w32_getregnames.jam
+++ /dev/null
@@ -1,17 +0,0 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO --- Testing W32_GETREGNAMES builtin... ;
-
-if $(NT)
-{
- assert "Beep" "ExtendedSounds"
- : (==) : [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ;
- assert "Beep" "ExtendedSounds"
- : (==) : [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ;
- assert "Control" "Enum" "Hardware Profiles" "Services"
- : (==) : [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" : subkeys ] ;
- assert "Control" "Enum" "Hardware Profiles" "Services"
- : (==) : [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ;
-}
diff --git a/tools/build/v2/test/engine/option_l.jam b/tools/build/v2/test/engine/option_l.jam
deleted file mode 100644
index 16299d631b..0000000000
--- a/tools/build/v2/test/engine/option_l.jam
+++ /dev/null
@@ -1,34 +0,0 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -l option... ;
-
- assert "...found 2 targets...
-...updating 1 target...
-.a. sleeper
-2 second time limit exceeded
-001
-
-echo 001
-sleep 4
-echo 002
-
-...failed .a. sleeper...
-...failed updating 1 target...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_l.jam -sBJAM_SUBTEST=1 -l2" ] ;
-}
-else
-{
- actions .a. {
-echo 001
-sleep 4
-echo 002
-}
-
- .a. sleeper ;
-
- DEPENDS all : sleeper ;
-}
diff --git a/tools/build/v2/test/engine/option_n.jam b/tools/build/v2/test/engine/option_n.jam
deleted file mode 100644
index 901dfed8db..0000000000
--- a/tools/build/v2/test/engine/option_n.jam
+++ /dev/null
@@ -1,44 +0,0 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -n option... ;
-
- assert "...found 4 targets...
-...updating 2 targets...
-.a. subtest_a
-
-echo [subtest_a] 0
-echo [subtest_a] 1
-echo [subtest_a] 2
-
-.a. subtest_b
-
-echo [subtest_b] 0
-echo [subtest_b] 1
-echo [subtest_b] 2
-
-...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_n.jam -sBJAM_SUBTEST=1 -n" ] ;
-}
-else
-{
- actions .a.
- {
-echo [$(<:B)] 0
-echo [$(<:B)] 1
-echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- DEPENDS all : subtest_a subtest_b ;
-}
diff --git a/tools/build/v2/test/engine/parallel_multifile_actions_1.jam b/tools/build/v2/test/engine/parallel_multifile_actions_1.jam
deleted file mode 100644
index d11de7a123..0000000000
--- a/tools/build/v2/test/engine/parallel_multifile_actions_1.jam
+++ /dev/null
@@ -1,45 +0,0 @@
-#~ Copyright 2007 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of multi-file actions - 1... ;
-
- assert "...found 6 targets...
-...updating 4 targets...
-.gen. g1.generated
-001
-002
-.use.1 u1.user
-003
-.use.2 u2.user
-004
-...updated 4 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_multifile_actions_1.jam -sBJAM_SUBTEST=1 -j2" ] ;
-}
-else
-{
- actions .gen. {
-echo 001
-sleep 4
-echo 002
-}
- rule .use.1 { DEPENDS $(<) : $(>) ; }
- actions .use.1 {
-echo 003
-}
- rule .use.2 { DEPENDS $(<) : $(>) ; }
- actions .use.2 {
-sleep 1
-echo 004
-}
-
- .gen. g1.generated g2.generated ;
- .use.1 u1.user : g1.generated ;
- .use.2 u2.user : g2.generated ;
-
- NOTFILE root ;
- DEPENDS g1.generated g2.generated : root ;
- DEPENDS all : u1.user u2.user ;
-}
diff --git a/tools/build/v2/test/engine/rule_param.jam b/tools/build/v2/test/engine/rule_param.jam
deleted file mode 100644
index 8bc51becf3..0000000000
--- a/tools/build/v2/test/engine/rule_param.jam
+++ /dev/null
@@ -1,60 +0,0 @@
-#~ Copyright 2008 Jonathan Biggar
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO -- Testing parameter passing... ;
-
-rule test_numeric_params
-{
- assert $(1) : (==) : 1 ;
- assert $(2) : (==) : 2 ;
- assert $(3) : (==) : 3 ;
- assert $(4) : (==) : 4 ;
- assert $(5) : (==) : 5 ;
- assert $(6) : (==) : 6 ;
- assert $(7) : (==) : 7 ;
- assert $(8) : (==) : 8 ;
- assert $(9) : (==) : 9 ;
- assert $(10) : (==) : 10 ;
- assert $(11) : (==) : 11 ;
- assert $(12) : (==) : 12 ;
- assert $(13) : (==) : 13 ;
- assert $(14) : (==) : 14 ;
- assert $(15) : (==) : 15 ;
- assert $(16) : (==) : 16 ;
- assert $(17) : (==) : 17 ;
- assert $(18) : (==) : 18 ;
- assert $(19) : (==) : 19 ;
-}
-
-rule test_named_params ( p1 : p2 : p3 : p4 : p5 : p6 : p7 : p8 : p9 :
- p10 : p11 : p12 : p13 : p14 : p15 : p16 : p17 : p18 : p19 )
-
-
-{
- assert $(p1) : (==) : 1 ;
- assert $(p2) : (==) : 2 ;
- assert $(p3) : (==) : 3 ;
- assert $(p4) : (==) : 4 ;
- assert $(p5) : (==) : 5 ;
- assert $(p6) : (==) : 6 ;
- assert $(p7) : (==) : 7 ;
- assert $(p8) : (==) : 8 ;
- assert $(p9) : (==) : 9 ;
- assert $(p10) : (==) : 10 ;
- assert $(p11) : (==) : 11 ;
- assert $(p12) : (==) : 12 ;
- assert $(p13) : (==) : 13 ;
- assert $(p14) : (==) : 14 ;
- assert $(p15) : (==) : 15 ;
- assert $(p16) : (==) : 16 ;
- assert $(p17) : (==) : 17 ;
- assert $(p18) : (==) : 18 ;
- assert $(p19) : (==) : 19 ;
-}
-
-test_numeric_params 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 :
- 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 ;
-
-test_named_params 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 :
- 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 ;
diff --git a/tools/build/v2/test/engine/stress_var_expand.jam b/tools/build/v2/test/engine/stress_var_expand.jam
deleted file mode 100644
index e76b36ab35..0000000000
--- a/tools/build/v2/test/engine/stress_var_expand.jam
+++ /dev/null
@@ -1,14 +0,0 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO --- Testing var expansion... ;
-
-local i = 0 ;
-local v = one two ;
-while $(i) != 4
-{
- i = [ CALC $(i) + 1 ] ;
- v = $(v)$(v) ;
- assert $(i) : (==) : $(i) ;
-}
diff --git a/tools/build/v2/test/engine/target_var.jam b/tools/build/v2/test/engine/target_var.jam
deleted file mode 100644
index d4fdae6314..0000000000
--- a/tools/build/v2/test/engine/target_var.jam
+++ /dev/null
@@ -1,16 +0,0 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO --- Testing var on target semantics... ;
-
-v on a = 1 ;
-v on b = 1 2 ;
-v on c = 1 2 3 ;
-v on d ?= 1 2 3 4 ;
-v on d ?= 5 6 7 8 ;
-v on a ?= 2 ;
-assert [ on a return $(v) ] : (==) : 1 ;
-assert [ on b return $(v) ] : (==) : 1 2 ;
-assert [ on c return $(v) ] : (==) : 1 2 3 ;
-assert [ on d return $(v) ] : (==) : 1 2 3 4 ;
diff --git a/tools/build/v2/test/engine/test.bat b/tools/build/v2/test/engine/test.bat
deleted file mode 100644
index a364fb50f3..0000000000
--- a/tools/build/v2/test/engine/test.bat
+++ /dev/null
@@ -1,53 +0,0 @@
-@ECHO OFF
-
-REM ~ Copyright 2006-2008 Rene Rivera.
-REM ~ Distributed under the Boost Software License, Version 1.0.
-REM ~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-REM ~ set BJAM=bjam
-REM ~ set BJAM_SRC=..\src
-REM ~ set BJAM_BIN=..\src\bin.ntx86\bjam.exe
-
-setlocal
-goto Start
-
-:Test_Path
-REM Tests for the given file(executable) presence in the directories in the PATH
-REM environment variable. Additionaly sets FOUND_PATH to the path of the
-REM found file.
-setlocal & endlocal & ver>NUL
-setlocal
-set test=%~$PATH:1
-endlocal
-if not errorlevel 1 set FOUND_PATH=%~dp$PATH:1
-goto :eof
-
-:Guess_BJAM
-setlocal & endlocal & ver>NUL
-if NOT "_%BJAM%_" == "__" goto :eof
-call :Test_Path bjam.exe
-if not errorlevel 1 (
- set BJAM=bjam.exe
- goto :eof)
-if "_%BJAM%_" == "__" (
- set BJAM=%BJAM_BIN%
- goto :eof)
-setlocal & endlocal & ver>NUL
-goto :eof
-
-:Build_BJAM_To_Test
-setlocal & endlocal & ver>NUL
-if "_%BJAM_SRC%_" == "__" set BJAM_SRC=..\src
-PUSHD %BJAM_SRC%
-call build.bat
-@ECHO OFF
-POPD
-set BJAM_BIN=%BJAM_SRC%\bin.ntx86\bjam.exe
-setlocal & endlocal & ver>NUL
-goto :eof
-
-:Start
-call :Build_BJAM_To_Test
-call :Guess_BJAM
-@ECHO ON
-%BJAM% -f test.jam "-sBJAM=%BJAM_BIN%"
diff --git a/tools/build/v2/test/engine/test.jam b/tools/build/v2/test/engine/test.jam
deleted file mode 100644
index f6f537766d..0000000000
--- a/tools/build/v2/test/engine/test.jam
+++ /dev/null
@@ -1,91 +0,0 @@
-#~ Copyright 2006-2008 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-TESTS =
- action_status
- actions_quietly
- builtin_normalize_path
- builtin_shell
- builtin_w32_getregnames
- option_d2
- option_l
- option_n
- parallel_actions
- parallel_multifile_actions_1
- parallel_multifile_actions_2
- rule_param
- stress_var_expand
- target_var
- var_expand
- ;
-
-BJAM ?= bjam ;
-
-#############################################################################
-
-if $(BJAM_RUN_TEST)
-{
- fail-count = 0 ;
- pass-count = 0 ;
-
- rule message ( message * )
- {
- local b = [ BACKTRACE ] ;
- ECHO "$(b[-4]):$(b[-3]):" $(message) ;
- }
-
-
- rule fail ( message * )
- {
- fail-count = [ CALC $(fail-count) + 1 ] ;
- message "error:" [FAILED] $(message) ;
- }
-
-
- rule pass ( message * )
- {
- pass-count = [ CALC $(pass-count) + 1 ] ;
- if --verbose in $(ARGV)
- {
- message "info:" [PASSED] $(message) ;
- }
- }
-
-
- rule assert ( expected * : test ? : obtained * )
- {
- test ?= "(==)" ;
- local r = 0 ;
- if $(test) = "(==)" && "*$(expected)*" != "*$(obtained)*"
- {
- fail '$(expected)' $(test) '$(obtained)' ;
- }
- else if $(test) = "(!=)" && "*$(expected)*" = "*$(obtained)*"
- {
- fail '$(expected)' $(test) '$(obtained)' ;
- }
- else
- {
- pass '$(expected)' $(test) '$(obtained)' ;
- }
- }
-
- include $(BJAM_RUN_TEST).jam ;
-
- EXIT --- $(BJAM_RUN_TEST): PASSED($(pass-count)) *FAILED($(fail-count))* : $(fail-count) ;
-}
-else
-{
- ECHO "Testing: $(BJAM)" ;
- fail-count = 0 ;
-
- for local test in $(TESTS)
- {
- local result = [ SHELL "\"$(BJAM)\" -f test.jam -sBJAM_RUN_TEST=$(test)" : exit-status ] ;
- fail-count = [ CALC $(fail-count) + $(result[1]) ] ;
- ECHO $(result[0]) ;
- }
-
- EXIT --- Complete: *FAILED($(fail-count))* : $(fail-count) ;
-}
diff --git a/tools/build/v2/test/engine/test.sh b/tools/build/v2/test/engine/test.sh
deleted file mode 100755
index 5c092836a7..0000000000
--- a/tools/build/v2/test/engine/test.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-#~ Copyright 2006-2008 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-#~ BJAM=bjam
-#~ BJAM_SRC=../src
-#~ BJAM_BIN=`ls -1 ${BJAM_SRC}/bin.*/bjam`
-
-# Run a command, and echo before doing so. Also checks the exit
-# status and quits if there was an error.
-echo_run ()
-{
- echo "$@"
- $@
- r=$?
- if test $r -ne 0 ; then
- exit $r
- fi
-}
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-Guess_BJAM ()
-{
- if test_path bjam ; then BJAM=bjam
- elif test -r ./bjam ; then BJAM=./bjam
- elif test -r "${BJAM_BIN}" ; then BJAM="${BJAM_BIN}"
- fi
-}
-
-Build_BJAM_To_Test ()
-{
- cwd=`pwd`
- if test "${BJAM_SRC}" = "" ; then BJAM_SRC=../src ; fi
- cd "${BJAM_SRC}"
- ./build.sh
- if test "${BJAM_BIN}" = "" ; then BJAM_BIN=`ls -1 ${BJAM_SRC}/bin.*/bjam` ; fi
- cd "${cwd}"
-}
-
-Build_BJAM_To_Test
-Guess_BJAM
-echo_run "${BJAM}" -f test.jam "-sBJAM=${BJAM_BIN}" "$@"
diff --git a/tools/build/v2/test/engine/var_expand.jam b/tools/build/v2/test/engine/var_expand.jam
deleted file mode 100644
index 00b03a0ce1..0000000000
--- a/tools/build/v2/test/engine/var_expand.jam
+++ /dev/null
@@ -1,19 +0,0 @@
-#~ Copyright 2006 Rene Rivera.
-#~ Distributed under the Boost Software License, Version 1.0.
-#~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-ECHO --- Testing var expansion... ;
-
-local p0 = name ;
-local p1 = dir/name ;
-local p2 = dir/sub/name ;
-
-assert name : (==) : $(p0:D=) ;
-assert name : (==) : $(p1:D=) ;
-assert name : (==) : $(p2:D=) ;
-assert "" : (==) : $(p0:D) ;
-assert dir : (==) : $(p1:D) ;
-assert dir/sub : (==) : $(p2:D) ;
-assert "" : (==) : $(p0:S) ;
-assert ($(p0)) : (==) : [ MATCH ^@(.*) : "@($(p0))" ] ;
-assert ($(p0)) : (==) : [ MATCH @(.*) : "--@($(p0))" ] ;
diff --git a/tools/build/v2/test/file_name_handling.py b/tools/build/v2/test/file_name_handling.py
deleted file mode 100755
index 8e59e6821a..0000000000
--- a/tools/build/v2/test/file_name_handling.py
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2008 Jurko Gospodnetic
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Tests Boost Jam & Boost Build's source & target file name handling. Originally
-# added as a regression test for a bug causing versions included in the Boost
-# library 1.35 release (and earlier) not handling Windows short file names
-# correctly. Also tests handling target file names containing spaces.
-
-# Implementation notes:
-#
-# We expect Boost Jam to automatically update the 'all' target when no target
-# has been explicitly specified on the command line.
-#
-# Windows short & long file names can not be matched until the file in
-# question actually exists so we need to create the file before running Boost
-# Jam.
-#
-# Currently Windows short file names are hardcoded but in case this proves
-# insufficient we should use the GetShortPathName() Windows API to get the
-# correct short file for a given long file name.
-# (30.04.2008.) (Jurko)
-
-import BoostBuild
-import os
-import time
-
-
-################################################################################
-#
-# prepare_file()
-# --------------
-#
-################################################################################
-
-def prepare_file(tester, target_name, age_in_seconds=0):
- """Prepares a new file with the given name, optionally setting its last
- access and modification timestamps to the given number of seconds in the
- history.
- """
- tester.write( target_name, "Original file content." )
- if ( ( not age_in_seconds is None ) and ( age_in_seconds != 0 ) ):
- t = time.time() - age_in_seconds
- os.utime( tester.native_file_name( target_name ), ( t, t ) )
-
-
-################################################################################
-#
-# test_simple_file_names()
-# ------------------------
-#
-################################################################################
-
-def test_simple_file_names():
- """Runs simple file name handling that is not expected to fail anywhere. Not
- really needed for regular testing but the test is really fast and its
- content may be used for comparing to other more complex test functions in
- this module which test the same system but with some potentially more
- problematic file names.
- """
- t = BoostBuild.Tester(pass_toolset=0)
-
- prepare_file(t, "source.txt" )
- prepare_file(t, "target.txt" , 120)
- prepare_file(t, "target_noupdate.txt", 240)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo "Modified file content ($(1:E=""))."> "$(1:E="")"
-}
-
-DEPENDS all : standaloneTarget.txt ;
-create-file standaloneTarget.txt : all ;
-
-DEPENDS all : target.txt ;
-DEPENDS target.txt : source.txt ;
-create-file target.txt ;
-
-NOUPDATE target_noupdate.txt ;
-DEPENDS all : target_noupdate.txt ;
-DEPENDS target_noupdate.txt : source.txt ;
-create-file target_noupdate.txt ;
-
-create-file shouldNotBeCreated1 ;
-create-file shouldNotBeCreated2 ;
-create-file shouldNotBeCreated3 ;
-""")
-
- t.run_build_system("-ftestScript.jam")
- t.expect_addition("standaloneTarget.txt")
- t.expect_modification("target.txt")
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_action()
-# ----------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_action():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to a Boost Jam action.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, long_file_name1)
- prepare_file(t, long_file_name2)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-ALWAYS "%(long_file_name1)s" ;
-DEPENDS all : "%(long_file_name1)s" ;
-create-file "%(long_file_name1)s" ;
-
-ALWAYS "%(long_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-create-file "%(short_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_modification(long_file_name2)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_ALWAYS()
-# ----------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_ALWAYS():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to the builtin ALWAYS rule.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, long_file_name1)
- prepare_file(t, long_file_name2)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-ALWAYS "%(long_file_name1)s" ;
-DEPENDS all : "%(long_file_name1)s" ;
-create-file "%(long_file_name1)s" ;
-
-ALWAYS "%(short_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-create-file "%(long_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_modification(long_file_name2)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_NOUPDATE()
-# ------------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_NOUPDATE():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to the builtin NOUPDATE rule.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should not be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, "source.txt" )
- prepare_file(t, long_file_name1, 120)
- prepare_file(t, long_file_name2, 120)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-DEPENDS all : "%(long_file_name1)s" ;
-DEPENDS "%(long_file_name1)s" : source.txt ;
-create-file "%(long_file_name1)s" ;
-
-NOUPDATE "%(short_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-DEPENDS "%(long_file_name2)s" : source.txt ;
-create-file "%(long_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# main()
-# ------
-#
-################################################################################
-
-test_simple_file_names()
-test_short_file_name_with_action()
-test_short_file_name_with_ALWAYS()
-test_short_file_name_with_NOUPDATE()
diff --git a/tools/build/v2/test/jamfile.jam b/tools/build/v2/test/jamfile.jam
deleted file mode 100644
index 9d186f3c1f..0000000000
--- a/tools/build/v2/test/jamfile.jam
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-# establish a project root right here in the test directory, so that we can test
-# things independently of the boost jambase, etc.
-project-root ;
-
-include check-test-tools.jam ;
-include check-jam-patches.jam ;
diff --git a/tools/build/v2/test/load_order.py b/tools/build/v2/test/load_order.py
index 34ceaaf448..183bf2440b 100644
--- a/tools/build/v2/test/load_order.py
+++ b/tools/build/v2/test/load_order.py
@@ -61,4 +61,28 @@ int main() {}
t.run_build_system(subdir="src/app")
t.expect_addition("src/app/bin/$toolset/debug/test.exe")
+# child/child2 used to be loaded before child
+t.rm(".")
+t.write("jamroot.jam", """
+use-project /child/child2 : child/child2 ;
+rule parent-rule ( )
+{
+ ECHO "Running parent-rule" ;
+}
+""")
+
+t.write("child/jamfile.jam", """
+""")
+
+t.write("child/child1/jamfile.jam", """
+""")
+
+t.write("child/child2/jamfile.jam", """
+parent-rule ;
+""")
+
+
+t.run_build_system(subdir="child/child1")
+t.expect_output_line("Running parent-rule")
+
t.cleanup()
diff --git a/tools/build/v2/test/m1-01.py b/tools/build/v2/test/m1-01.py
deleted file mode 100644
index 6c42c1eec8..0000000000
--- a/tools/build/v2/test/m1-01.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Test the very basic 'make' functionality.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-# Check that we can build something.
-t.run_build_system("-sTOOLSET=yfc")
-
-t.expect_addition("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-# Check that we have vanilla target names available.
-t.touch("a.cpp")
-t.run_build_system("-sTOOLSET a.obj")
-t.expect_touch("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_no_modification("bin/a/yfc/debug/runtime-link-dynamic/a")
-
-
-# Check that if a build request cannot be completely matches, a warning is
-# issued and a subvariant with link-compatible properties is used.
-t.write("jamfile.jam", t.read("jamfile2.jam"))
-stdout="""Warning: cannot exactly satisfy request for ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Using
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-instead.
-""")
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-# Check that conflicting link-incompatible requirements prevent building.
-t.write("jamfile.jam", t.read("jamfile3.jam"))
-stdout="""Warning: cannot satisfy request for ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Nothing will be built.
-""")
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout, status=1)
-
-t.pass_test()
diff --git a/tools/build/v2/test/m1-02.py b/tools/build/v2/test/m1-02.py
deleted file mode 100644
index 13cc9dc1ae..0000000000
--- a/tools/build/v2/test/m1-02.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Tests that 'make' accepts targets from other directories and that build
-# requests for those targets can be overriden.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-t.run_build_system("-sTOOLSET=yfc")
-
-t.expect_addition("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/b.obj") !=\
-"""
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-# Check that we have vanilla target names available in subdirs.
-t.touch("auxillary/b.cpp")
-t.run_build_system("-sTOOLSET b.obj", subdir="auxillary")
-t.expect_touch("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_no_modification("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_no_modification("bin/a/yfc/debug/runtime-link-dynamic/a")
-
-
-# Check that we can not request link-incompatible property for source target.
-t.write('jamfile.jam', t.read('jamfile2.jam'))
-stdout="""Error: subvariant of target ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-requests link-incompatible property
- <rtti>off
-for source @auxillary/b.obj
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-# Check that if we request link-compatible property then requirement for the
-# source target will override it, with a warning. This is similar to the way
-# build requests are satisfied (see the first test).
-#
-# CONSIDER: should be print the main target which requests this one (and
-# modifies requirements)?
-t.write('jamfile.jam', t.read('jamfile3.jam'))
-t.write('auxillary/jamfile.jam', t.read('auxillary/jamfile3.jam'))
-stdout="""Warning: cannot exactly satisfy request for auxillary/b.obj with properties
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Using
- <optimization>speed <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-instead.
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-# Check for link-incompatible properties.
-t.write('jamfile.jam', t.read('jamfile4.jam'))
-t.write('auxillary/jamfile.jam', t.read('auxillary/jamfile4.jam'))
-stdout="""Warning: cannot satisfy request for auxillary/b.obj with properties
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Nothing will be built.
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-t.pass_test()
diff --git a/tools/build/v2/test/m1-03.py b/tools/build/v2/test/m1-03.py
deleted file mode 100644
index 2f31ba27c8..0000000000
--- a/tools/build/v2/test/m1-03.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Tests that we can use objects from other projects, i.e. with other project
-# root. Test also that we can refer to those target using project-id.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-t.run_build_system("-sTOOLSET=yfc", subdir="p1")
-
-t.expect_addition("p1/bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("p1/auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_addition("p2/bin/c.obj/yfc/debug/runtime-link-dynamic/c.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("p1/bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("p1/auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/b.obj") !=\
-"""
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-t.fail(t.read("p2/bin/c.obj/yfc/debug/runtime-link-dynamic/c.obj") !=\
-"""
-<include>everything <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-<include>everything <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-c.cpp
-""")
-
-t.expect_nothing_more()
-
-# TODO: need to write test cases for referring to targets using project-id.
-
-t.pass_test()
diff --git a/tools/build/v2/test/prebuilt/ext/jamfile2.jam b/tools/build/v2/test/prebuilt/ext/jamfile2.jam
index dd79f4ea2d..cd59663d6d 100644
--- a/tools/build/v2/test/prebuilt/ext/jamfile2.jam
+++ b/tools/build/v2/test/prebuilt/ext/jamfile2.jam
@@ -1,9 +1,9 @@
-import modules ;
+import os ;
local dll-suffix = so ;
local prefix = "" ;
-if [ modules.peek : OS ] in CYGWIN NT
+if [ os.name ] in CYGWIN NT
{
if [ MATCH ^(gcc) : $toolset ]
{
diff --git a/tools/build/v2/test/prebuilt/ext/jamfile3.jam b/tools/build/v2/test/prebuilt/ext/jamfile3.jam
index f172a89d08..a373a5fb21 100644
--- a/tools/build/v2/test/prebuilt/ext/jamfile3.jam
+++ b/tools/build/v2/test/prebuilt/ext/jamfile3.jam
@@ -3,11 +3,11 @@
# it tries to access prebuilt targets using absolute
# paths. It used to be broken on Windows.
-import modules ;
+import os ;
local dll-suffix = so ;
local prefix = "" ;
-if [ modules.peek : OS ] in CYGWIN NT
+if [ os.name ] in CYGWIN NT
{
if [ MATCH ^(gcc) : $toolset ]
{
diff --git a/tools/build/v2/test/project-test1.jam b/tools/build/v2/test/project-test1.jam
deleted file mode 100644
index c2d6ae5763..0000000000
--- a/tools/build/v2/test/project-test1.jam
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2002, 2003 Dave Abrahams
-# Copyright 2002 Rene Rivera
-# Copyright 2002, 2003 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import project ;
-import targets ;
-import assert ;
-
-project.load project-test1 ;
-import project-roots ;
-
-project-roots.print ;
-
-NOTFILE all ;
-
-
diff --git a/tools/build/v2/test/project-test1/dir/jamfile.jam b/tools/build/v2/test/project-test1/dir/jamfile.jam
deleted file mode 100644
index 3434eb7911..0000000000
--- a/tools/build/v2/test/project-test1/dir/jamfile.jam
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2003 Dave Abrahams
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-project /boost-build-test-project-1/dir
- : source-location src
- : default-build release
- ;
diff --git a/tools/build/v2/test/project-test1/dir2/jamroot.jam b/tools/build/v2/test/project-test1/dir2/jamroot.jam
deleted file mode 100644
index 8cfc3a28e9..0000000000
--- a/tools/build/v2/test/project-test1/dir2/jamroot.jam
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
diff --git a/tools/build/v2/test/project-test1/jamfile.jam b/tools/build/v2/test/project-test1/jamfile.jam
deleted file mode 100644
index d343ba6df6..0000000000
--- a/tools/build/v2/test/project-test1/jamfile.jam
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-project /boost-build-test-project-1
- : requirements <threading>multi <include>/home/ghost/local/include ;
-
-build-project dir2 ;
-build-project dir ;
diff --git a/tools/build/v2/test/project-test1/jamroot.jam b/tools/build/v2/test/project-test1/jamroot.jam
deleted file mode 100644
index a61a11c1d5..0000000000
--- a/tools/build/v2/test/project-test1/jamroot.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-import builtin ;
diff --git a/tools/build/v2/test/project-test1/project-test1.jam b/tools/build/v2/test/project-test1/project-test1.jam
deleted file mode 100644
index 2f2aad25c8..0000000000
--- a/tools/build/v2/test/project-test1/project-test1.jam
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2002, 2003 Dave Abrahams
-# Copyright 2002, 2003 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import project ;
-import targets ;
-import assert ;
-import project-roots ;
-
-project.load "." ;
-
-import standalone-project ;
-
-project-roots.print ;
-
-assert.result standalone-project : project.find /teeest : "." ;
-
-NOTFILE all ;
-
-
diff --git a/tools/build/v2/test/project-test1/readme.txt b/tools/build/v2/test/project-test1/readme.txt
deleted file mode 100644
index 0001799243..0000000000
--- a/tools/build/v2/test/project-test1/readme.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Copyright 2003 Dave Abrahams
-Copyright 2002 Vladimir Prus
-Distributed under the Boost Software License, Version 1.0.
-(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-This tests for basic project handling -- declaring subprojects, finding
-parent projects and project roots and for working project-ids.
diff --git a/tools/build/v2/test/project-test1/standalone-project.jam b/tools/build/v2/test/project-test1/standalone-project.jam
deleted file mode 100644
index 48249b561d..0000000000
--- a/tools/build/v2/test/project-test1/standalone-project.jam
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2003 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-
-import project ;
-
-# Convert ourself into a real project.
-project.initialize $(__name__) ;
-
-# Now we can identify ourselfs.
-project /teeest ;
diff --git a/tools/build/v2/test/project_test1.py b/tools/build/v2/test/project_test1.py
deleted file mode 100644
index a2a2ada186..0000000000
--- a/tools/build/v2/test/project_test1.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Dave Abrahams
-# Copyright 2002, 2003, 2004 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import BoostBuild
-import os
-
-t = BoostBuild.Tester("--build-system=project-test1", boost_build_path='',
- pass_toolset=0)
-
-# This test does no modifications, so run in in the invocation dir.
-os.chdir(t.original_workdir)
-
-expected_output1="""Project Roots:
-
-"""
-
-expected_output2="""'%(root-dir-prefix)sdir2':
-
- Module for project-root is 'project-root<%(root-dir-prefix)sdir2>'
-
-Projects:
-
-'/cool-library':
-
-* Parent project: (none)
-* Requirements: <include>/home/ghost/build/boost-cvs
-* Default build:
-* Source location: %(root-dir-prefix)sdir2
-* Projects to build:
-
-"""
-
-expected_output3="""'%(root-dir)s':
-
- Module for project-root is 'project-root<%(root-dir)s>'
-
-Projects:
-
-'/boost-build-test-project-1':
-
-* Parent project: (none)
-* Requirements: <include>/home/ghost/local/include <threading>multi
-* Default build:
-* Source location: %(root-dir)s
-* Projects to build: dir dir2
-
-'/boost-build-test-project-1/dir':
-
-* Parent project: %(root-dir)s
-* Requirements: <include>/home/ghost/local/include <threading>multi
-* Default build: <variant>release
-* Source location: %(root-dir-prefix)sdir/src
-* Projects to build:
-
-"""
-
-# Test that correct project structure is created when jam is invoked outside of
-# the source tree.
-expected = (expected_output1 + expected_output2 + expected_output3) % \
- {"root-dir": "project-test1",
- "root-dir-prefix": "project-test1/" }
-
-t.run_build_system(stdout=expected)
-
-# Test that correct project structure is created when jam is invoked at the top
-# of the source tree.
-expected = (expected_output1 + expected_output3 + expected_output2) % \
- {"root-dir": ".",
- "root-dir-prefix": "" }
-
-os.chdir("project-test1")
-t.run_build_system(stdout=expected)
-
-t.cleanup()
diff --git a/tools/build/v2/test/recursive.jam b/tools/build/v2/test/recursive.jam
deleted file mode 100644
index 8087f7da75..0000000000
--- a/tools/build/v2/test/recursive.jam
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright 2001, 2002 Dave Abrahams
-# Copyright 2005 Rene Rivera
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-##############################################################
-# Rules and actions that test Jam by invoking it recursively #
-# #
-# This is necessary for testing anything that requires Jam #
-# to execute build actions whose results must be checked, #
-# and anything which exits Jam with a failure code (e.g. a #
-# failed assertion). #
-##############################################################
-
-# Creates a fake target, always built, which succeeds in building if Invoking a
-# Jamfile containing the given string succeeds. If optional-expected-output is
-# supplied, creates another fake target which succeeds in building if
-# optional-expected-output is in the Jam output.
-#
-# RETURNS: the target name of the Jam command.
-rule Jam ( command : expected-output ? )
-{
- local jam-cmd = "$(command:G=jam_command)" ;
-
- NOTFILE "$(jam-cmd)" ;
- ALWAYS "$(jam-cmd)" ;
- DEPENDS all : "$(jam-cmd)" ;
-
- if ($NT)
- {
- redirect on $(jam-cmd) = "nul" ;
- }
- else if $(UNIX)
- {
- redirect on $(jam-cmd) = "/dev/null" ;
- }
-
- if $(VERBOSE)
- {
- redirect on $(jam-cmd) = ;
- }
-
- invoke-Jam "$(jam-cmd)" ;
-
- if $(expected-output)
- {
- redirect on $(jam-cmd) = "scratch-output.txt" ;
- local output-target = "$(expected-output:G=$(command))" ;
- NOTFILE "$(output-target)" ;
- ALWAYS "$(output-target)" ;
- DEPENDS all : "$(output-target)" ;
- Expect-in-output "$(output-target)" ;
-
- if $(VERBOSE)
- {
- if $(NT) { VERBOSE on $(output-target) = "type " ; }
- else { VERBOSE on $(output-target) = "cat " ; }
- }
- }
- return $(jam-cmd) ;
-}
-
-# Just like the "Jam" rule, above, but only succeeds if the Jam command /fails/.
-rule Jam-fail ( command : expected-output ? )
-{
- local target = [ Jam $(command) : $(expected-output) ] ;
- FAIL_EXPECTED $(target) ;
- return $(target) ;
-}
-
-# The temporary jamfile we write is called "temp.jam". If the user has set
-# BOOST_BUILD_ROOT, it will be built there.
-gBOOST_TEST_JAMFILE = temp.jam ;
-LOCATE on gBOOST_TEST_JAMFILE ?= $(BOOST_BUILD_ROOT) ;
-
-# Runs Jam on a temporary Jamfile which contains the string in $(command:G=)
-# and redirects the results into a file whose name is given by $(redirect) on
-# command
-rule invoke-Jam ( command )
-{
- PREFIX on $(command) = "actions unbuilt { } unbuilt all ;" ;
- if $(NT)
- {
- REMOVE on $(command) = $(SystemRoot)\System32\find ;
- }
- REMOVE on $(command) ?= rm ;
-}
-actions invoke-Jam
-{
- echo $(PREFIX) $(<:G=) > $(gBOOST_TEST_JAMFILE)
- jam -sBOOST_ROOT=../../.. -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect)
-}
-# $(REMOVE) $(gBOOST_TEST_JAMFILE)
-
-
-# These actions expect to find the ungristed part of $(<) in scratch-output.txt
-# and return a nonzero exit code otherwise
-if $(NT)
-{
- # Explicitly get the NT find command in case someone has another find in their path.
- actions quietly Expect-in-output
- {
- $(VERBOSE)scratch-output.txt ;
- $(SystemRoot)\System32\find /C "$(<:G=)" scratch-output.txt >nul
- }
-}
-else
-{
- # Not really the right actions for Unix; the argument will be interpreted as
- # a regular expression. Is there a simpler find?
- actions quietly Expect-in-output
- {
- $(VERBOSE)scratch-output.txt;
- grep "$(<:G=)" scratch-output.txt
- }
-}
-
diff --git a/tools/build/v2/test/startup_v1.py b/tools/build/v2/test/startup_v1.py
deleted file mode 100644
index 14a286a70f..0000000000
--- a/tools/build/v2/test/startup_v1.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Dave Abrahams
-# Copyright 2003, 2004, 2005 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import BoostBuild
-import os
-import re
-
-def expect_substring(actual, expected):
- return actual.find(expected) != -1
-
-def match_re(actual, expected):
- return re.match(expected, actual, re.DOTALL) != None
-
-# Test the v1 startup behavior.
-t = BoostBuild.Tester(executable='bjam', match=match_re, boost_build_path='',
- pass_toolset=0)
-
-t.set_tree('startup')
-
-#if os.name == 'nt':
-# t.run_build_system(
-# status=1, stdout="You didn't set BOOST_ROOT", match = expect_substring)
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost\.Build: could not find ''' +
- r'''"boost-build\.jam".''')
-
-os.chdir('no-bootstrap1')
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"''')
-
-# Descend to a subdirectory which /doesn't/ contain a boost-build.jam
-# file, and try again to test the crawl-up behavior.
-os.chdir('subdir')
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"''')
-
-os.chdir('../../no-bootstrap2')
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build \. ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"''')
-
-os.chdir('../no-bootstrap3')
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost.Build
-.*boost-build.jam" was found.*
-However, it failed to call the "boost-build" rule''')
-
-# test bootstrapping based on BOOST_BUILD_PATH
-os.chdir('../bootstrap-env')
-t.run_build_system(extra_args='-sBOOST_ROOT=../boost-root ' +
- '-sBOOST_BUILD_PATH=../boost-root/build',
- stdout='build system bootstrapped')
-
-# test bootstrapping based on an explicit path in boost-build.jam
-os.chdir('../bootstrap-explicit')
-t.run_build_system(extra_args='-sBOOST_ROOT=../boost-root',
- stdout='build system bootstrapped')
-
-# test bootstrapping based on BOOST_ROOT
-os.chdir('../bootstrap-implicit')
-t.run_build_system(extra_args='-sBOOST_ROOT=../boost-root',
- stdout='build system bootstrapped')
-
-t.cleanup()
diff --git a/tools/build/v2/test/subdir1/file-to-bind b/tools/build/v2/test/subdir1/file-to-bind
deleted file mode 100644
index 7ff128fa69..0000000000
--- a/tools/build/v2/test/subdir1/file-to-bind
+++ /dev/null
@@ -1 +0,0 @@
-# This file intentionally left blank \ No newline at end of file
diff --git a/tools/build/v2/test/test.jam b/tools/build/v2/test/test.jam
index 5e1aae9bcd..1ae1a2059e 100644
--- a/tools/build/v2/test/test.jam
+++ b/tools/build/v2/test/test.jam
@@ -4,20 +4,36 @@
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+# util
+import assert ;
+import container ;
import indirect ;
-import string ;
import numbers ;
-import sequence ;
-import "class" ;
+import order ;
import os ;
import path ;
+import print ;
+import regex ;
+import sequence ;
+import set ;
+import string ;
+import utility ;
+
+# kernel
+import "class" ;
+import errors ;
+import modules ;
+
+# build
+import build-request ;
import feature ;
import property ;
-import build-request ;
-import container ;
-import print ;
-import common ;
+import toolset ;
+import type ;
+import version ;
+# tools
+import common ;
actions nothing { }
nothing all ;
diff --git a/tools/build/v2/test/test1.py b/tools/build/v2/test/test1.py
index 3cdc71d2d2..05b3966483 100644
--- a/tools/build/v2/test/test1.py
+++ b/tools/build/v2/test/test1.py
@@ -6,7 +6,7 @@
import BoostBuild
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(pass_toolset=0)
t.write("test.jam", """
actions unbuilt { }
@@ -15,4 +15,4 @@ ECHO "Hi" ;
""")
t.run_build_system("-ftest.jam", stdout="Hi\n")
-t.pass_test()
+t.cleanup()
diff --git a/tools/build/v2/test/test2.py b/tools/build/v2/test/test2.py
index b5c9ba824e..938b36545a 100644
--- a/tools/build/v2/test/test2.py
+++ b/tools/build/v2/test/test2.py
@@ -11,7 +11,7 @@ t = BoostBuild.Tester()
t.set_tree("test2")
-file_list = 'bin/foo/$toolset/debug/runtime-link-dynamic/' * \
+file_list = 'bin/$toolset/debug/' * \
BoostBuild.List("foo foo.o")
t.run_build_system("-sBOOST_BUILD_PATH=" + t.original_workdir + "/..")
@@ -22,4 +22,4 @@ t.write("foo.cpp", "int main() {}\n")
t.run_build_system("-d2 -sBOOST_BUILD_PATH=" + t.original_workdir + "/..")
t.expect_touch(file_list)
-t.pass_test()
+t.cleanup()
diff --git a/tools/build/v2/test/test2/Jamrules b/tools/build/v2/test/test2/Jamrules
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tools/build/v2/test/test2/Jamrules
+++ /dev/null
diff --git a/tools/build/v2/test/test2/jamfile.jam b/tools/build/v2/test/test2/jamroot.jam
index 670583964e..4fb3f28865 100644
--- a/tools/build/v2/test/test2/jamfile.jam
+++ b/tools/build/v2/test/test2/jamroot.jam
@@ -2,7 +2,4 @@
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-project-root ;
-
exe foo : foo.cpp ;
diff --git a/tools/build/v2/test/test_all.py b/tools/build/v2/test/test_all.py
index 59476bd740..b6aad705d9 100644
--- a/tools/build/v2/test/test_all.py
+++ b/tools/build/v2/test/test_all.py
@@ -118,10 +118,10 @@ def reorder_tests(tests, first_test):
return tests
-critical_tests = ["unit_tests", "module_actions", "startup_v1", "startup_v2"]
+critical_tests = ["unit_tests", "module_actions", "startup_v2"]
critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
- "core_varnames", "core_import_module"]
+ "core_language", "core_arguments", "core_varnames", "core_import_module"]
tests = [ "absolute_sources",
"alias",
@@ -130,6 +130,8 @@ tests = [ "absolute_sources",
"build_dir",
"build_file",
"build_no",
+ "builtin_echo",
+ "builtin_exit",
"c_file",
"chain",
"clean",
@@ -140,6 +142,18 @@ tests = [ "absolute_sources",
"conditionals_multiple",
"configuration",
"copy_time",
+ "core_action_status",
+ "core_actions_quietly",
+ "core_at_file",
+ "core_bindrule",
+ "core_nt_line_length",
+ "core_option_d2",
+ "core_option_l",
+ "core_option_n",
+ "core_parallel_actions",
+ "core_parallel_multifile_actions_1",
+ "core_parallel_multifile_actions_2",
+ "core_update_now",
"custom_generator",
"default_build",
"default_features",
@@ -147,6 +161,7 @@ tests = [ "absolute_sources",
# "default_toolset",
"dependency_property",
"dependency_test",
+ "direct_request_test",
"disambiguation",
"dll_path",
"double_loading",
@@ -155,7 +170,6 @@ tests = [ "absolute_sources",
"example_make",
"expansion",
"explicit",
- "file_name_handling",
"free_features_request",
"generator_selection",
"generators_test",
@@ -202,6 +216,7 @@ tests = [ "absolute_sources",
"testing_support",
"timedata",
"unit_test",
+ "unused",
"use_requirements",
"using",
"wrapper",
diff --git a/tools/build/v2/test/testing-primitives/boost-build.jam b/tools/build/v2/test/testing-primitives/boost-build.jam
deleted file mode 100644
index 667355a164..0000000000
--- a/tools/build/v2/test/testing-primitives/boost-build.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-boost-build . ;
diff --git a/tools/build/v2/test/testing-primitives/bootstrap.jam b/tools/build/v2/test/testing-primitives/bootstrap.jam
deleted file mode 100644
index 2b1ad48542..0000000000
--- a/tools/build/v2/test/testing-primitives/bootstrap.jam
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# Proof-of-concept for bjam-based testing mechanism. This file should
-# work on NT, Cygwin, and Linux. No promises for other platforms.
-
-# Set a variable which says how to dump a file to stdout
-if $(NT)
-{
- CATENATE = type ;
-}
-else
-{
- CATENATE = cat ;
-}
-
-# invoke the given action rule `act' to build target from sources
-rule do-make ( target : sources * : act )
-{
- DEPENDS $(target) : $(sources) ;
- $(act) $(target) : $(sources) ;
-}
-
-# top-level version of do-make which causes target to be built by
-# default
-rule make ( target : sources * : act )
-{
- DEPENDS all : $(target) ;
- do-make $(target) : $(sources) : $(act) ;
-}
-
-# cause `target' to exist and building to succeed if invoking
-#
-# $(act) $(target) : $(sources)
-#
-# fails, and to fail if the action succeeds.
-rule make-fail ( target : sources * : act )
-{
- # Establish another logical target which refers to the same file,
- # by using different grist.
- DEPENDS all : <different-grist>$(target) ;
-
- # Make the new logical target depend on the target
- DEPENDS <different-grist>$(target) : $(target) ;
-
- # Cause the target to be built from sources using $(act).
- do-make $(target) : $(sources) : $(act) ;
-
- # Note that we expect target to fail to build
- FAIL_EXPECTED $(target) ;
-
- # Build a failure marker file. Because targets are only built if
- # all their dependents "succeed", the marker will only be
- # generated if $(target) failed to build, as expected.
- failure-marker <different-grist>$(target) ;
-}
-
-# Simple action rules which write text into the target. Different
-# names for different purposes.
-actions failure-marker
-{
- echo failed as expected > $(<)
-}
-
-actions create
-{
- echo creating > $(<)
-}
-
-# An action which will always fail, for testing expected failure rules
-actions fail-to-create
-{
- exit 1
-}
-
-# Basic rule-action pair which builds the target by executing the
-# given commands
-rule do-run ( target : commands + )
-{
- COMMANDS on $(target) = $(commands) ;
- NOTFILE $(commands) ;
-}
-
-# Run commands, leaving the output behind in $(<:S=.out). Echo to
-# stdout if the command fails.
-#
-# Detailed explanation:
-#
-# $(COMMANDS) Run commands
-# > $(<:S=.out) into the output file
-# 2>&1 including stderr
-# && and if that succeeds
-# cp -f $(<:S=.out) $(<) copy the output file into the target
-# || otherwise
-# ( $(CATENATE) $(<:S=.out) dump any output to stdout
-# && exit 1 and exit with an error code
-# )
-actions do-run
-{
- $(COMMANDS) > $(<:S=.out) 2>&1 && cp -f $(<:S=.out) $(<) || ( $(CATENATE) $(<:S=.out) && exit 1 )
-}
-
-# top-level version of do-run which causes target to be built by
-# default
-rule run ( target : commands + )
-{
- DEPENDS all : $(target) ;
- do-run $(target) : $(commands) ;
-}
-
-# experimental expected-failure version of run. This doesn't have
-# quite the right semantics w.r.t. output dumping (it is still only
-# dumped if the run fails), but we don't need run-fail anyway so it
-# doesn't matter too much.
-rule run-fail ( target : commands + )
-{
- make-fail $(target) : $(commands) : do-run ;
-}
-
-# A command which will always fail to run. There is no file called
-# nonexistent, so executing $(error) always causes an error. We can't
-# just use `exit 1' below because that will cause all command
-# processing to stop, and we want the rest of the do-run action
-# command-line to execute.
-error = $(CATENATE)" nonexistent" ;
-
-make-fail t1.txt : : create ;
-make-fail t2.txt : : fail-to-create ;
-make t3.txt : : create ;
-make t4.txt : : fail-to-create ;
-
-run t5.txt : "( echo failing t5 && $(error) )" ;
-run t6.txt : echo hi ;
-
-run-fail t7.txt : "( echo failing t7 && $(error) )" ;
-run-fail t8.txt : echo hi ;
diff --git a/tools/build/v2/test/testing_primitives.py b/tools/build/v2/test/testing_primitives.py
deleted file mode 100644
index ae62993b32..0000000000
--- a/tools/build/v2/test/testing_primitives.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import BoostBuild
-import re
-
-def match_re(actual, expected):
- return re.match(expected, actual, re.DOTALL) != None
-
-t = BoostBuild.Tester(match=match_re)
-
-t.set_tree('testing-primitives')
-
-# We expect t5 and t7's output to be dumped to stdout.
-t.run_build_system(stdout=r'''.*failing t5.*failing t7''')
-
-t.expect_addition('t2.txt')
-t.expect_addition('t3.txt')
-t.expect_addition('t5.out')
-t.expect_addition('t6.out')
-t.expect_addition('t6.txt')
-t.expect_addition('t7.out')
-t.expect_addition('t7.txt')
-t.expect_addition('t8.out')
-t.expect_nothing_more()
-
-t.cleanup()
diff --git a/tools/build/v2/test/unit-tests.jam b/tools/build/v2/test/unit-tests.jam
deleted file mode 100644
index 212f4c3887..0000000000
--- a/tools/build/v2/test/unit-tests.jam
+++ /dev/null
@@ -1,262 +0,0 @@
-# Copyright 2001 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# assert_equal a : b
-#
-# exits with an assertion failure if a != b
-rule assert_equal
-{
- if $(<) != $(>)
- {
- EXIT "assertion failure: [" $(<) "] != [" $(>) "]" ;
- }
-}
-
-rule assert_equal_sets
-{
- if ! [ equal-sets $(<) : $(>) ]
- {
- EXIT "assertion failure: [" $(<) "] !=(set) [" $(>) "]" ;
- }
-}
-
-# FAppendSuffix
-assert_equal [ FAppendSuffix yacc lex foo.bat : ] : yacc lex foo.bat ;
-assert_equal [ FAppendSuffix yacc lex foo.bat : .exe ] : yacc.exe lex.exe foo.bat ;
-assert_equal [ FAppendSuffix yacc lex foo.bat : .dll .lib ] : yacc.dll yacc.lib lex.dll lex.lib foo.bat foo.lib ;
-
-# sort
-assert_equal [ sort 7 3 5 6 2 4 ] : 2 3 4 5 6 7 ;
-
-# min
-assert_equal [ min 7 3 5 6 2 4 ] : 2 ;
-
-# difference
-assert_equal [ difference 0 1 2 3 4 5 6 7 8 9 : 2 3 5 7 ] : 0 1 4 6 8 9 ;
-
-# replace
-assert_equal [ replace 1 3 5 7 7 9 2 5 4 3 1 : 7 x ] : 1 3 5 x x 9 2 5 4 3 1 ;
-
-# select-ungristed
-assert_equal [ select-ungristed <a>b c <d>e f ] : c f ;
-
-# split-qualified-property
-assert_equal [ split-qualified-property <feature>value ]
- : <*> <*> <feature>value ;
-
-assert_equal [ split-qualified-property <variant><feature>value ]
- : <*> <variant> <feature>value ;
-
-assert_equal [ split-qualified-property <toolset><variant><feature>value ]
- : <toolset> <variant> <feature>value ;
-
-# unique
-assert_equal [ unique 0 1 2 3 1 7 6 6 4 5 ] : 0 1 2 3 7 6 4 5 ;
-
-# get-properties
-assert_equal [ get-properties <foo> <bar> : <foo>bar <foo>baz <bar>fight <baz>niss ]
- : <foo>bar <foo>baz <bar>fight ;
-
-# get-values
-assert_equal [ get-values <foo> : <foo>bar <foo>baz <bar>fight <baz>niss ] : bar baz ;
-
-# normalize-properties
-assert_equal [ normalize-properties <a>b <c><d>e <f><g><h>i ] :
- <*><*><a>b <*><c><d>e <f><g><h>i ;
-
-# intersection
-assert_equal [ intersection 1 2 2 3 3 4 5 6 7 : 5 1 3 7 3 9 11 ] : 1 3 3 5 7 ;
-
-# is-subset
-assert_equal [ is-subset a b c : c a b d ] : true ;
-assert_equal [ is-subset a b z : c a b d ] : ;
-
-# split-path
-assert_equal [ split-path <a>b/c/<d>e ] : <a>b c <d>e ;
-assert_equal [ split-path <a>/<d>/<e> ] : <a> <d> <e> ;
-assert_equal [ split-path <a> ] : <a> ;
-assert_equal [ split-path x ] : x ;
-assert_equal [ split-path $(DOT) ] : $(DOT) ;
-assert_equal [ split-path a/b.c/d.e/f ] : a b.c d.e f ;
-if $(NT)
-{
- assert_equal [ split-path x:\\y\\z\\w ] : x: y z w ;
- assert_equal [ split-path x:\\y\\z ] : x: y z ;
- assert_equal [ split-path x:\\y ] : x: y ;
- assert_equal [ split-path x:\\ ] : x: ;
- assert_equal [ split-path x: ] : x: ;
-}
-
-# distribute-feature
-assert_equal [ distribute-feature <feature>value1 ] : <feature>value1 ;
-assert_equal [ distribute-feature <feature>value1/value2 ] : <feature>value1 <feature>value2 ;
-assert_equal [ distribute-feature <feature>value1/value2/value3 ] : <feature>value1 <feature>value2 <feature>value3 ;
-
-# segregate-free-properties
-{
- local gFREE_FEATURES = <a> <c> <e> ;
- local x = <a>b <b>c <d>e ;
- local y = <a>b <a>c <b>c <e>f ;
- local free = [ segregate-free-properties x y ] ;
- assert_equal $(free) : <a>b <a>c <e>f ;
- assert_equal $(x) : <b>c <d>e ;
- assert_equal $(y) : <b>c ;
-}
-
-# set-insert
-{
- local gTEST_SET = 1 2 3 ;
- set-insert gTEST_SET : 2 ;
- assert_equal $(gTEST_SET) : 1 2 3 ;
- set-insert gTEST_SET : 0 ;
- assert_equal $(gTEST_SET) : 1 2 3 0 ;
-}
-
-# equal-sets
-assert_equal [ equal-sets 1 2 3 : 3 2 2 1 ] : true ;
-assert_equal [ equal-sets 1 2 3 3 : 3 2 2 1 ] : true ;
-assert_equal [ equal-sets 1 2 3 3 4 : 3 2 2 1 ] : ;
-
-# segregate-overrides
-{
- local base = <a>b <c>d <e>f ;
- local overrides = <a>b <c>c <d>e <f>g ;
- segregate-overrides overrides : base ;
- assert_equal $(overrides) : <c>c <d>e <f>g ;
- assert_equal $(base) : <a>b <e>f ;
-}
-
-# select-properties
-{
- local TOOLS = gcc msvc ;
-
- local gRELEVANT_FEATURES(msvc) = <debug-symbols> <optimization> <inlining> <inline> <runtime-build> <runtime-link> <threading> <define> <undef> <include> <target-type> ;
- local gRELEVANT_FEATURES(gcc) = <runtime-link> <debug-symbols> <optimization> <inlining> <profiling> <define> <undef> <include> <shared-linkable> <target-type> ;
- local gFREE_FEATURES = <define> <undef> <include> ;
-
- local gBASE_PROPERTIES(msvc,debug) = <debug-symbols>on <inlining>off <optimization>off <runtime-build>debug <threading>single ;
- local gBASE_PROPERTIES(gcc,debug) = <debug-symbols>on <inlining>off <optimization>off <profiling>off <shared-linkable>false ;
- local gBASE_PROPERTIES(msvc,release) = <debug-symbols>off <define>NDEBUG <inlining>full <optimization>speed <runtime-build>release <threading>single ;
- local gBASE_PROPERTIES(gcc,release) = <debug-symbols>off <define>NDEBUG <inlining>full <optimization>speed <profiling>off <shared-linkable>false ;
-
- local TEST_PROPERTIES = <inlining>off <define>FOO <*><release><inlining>on
- <debug><define>DEBUG <msvc><release><foo>bar
- <gcc><*><inlining>on
- <msvc><*><foo>baz
- <msvc><release><optimization>speed
- <msvc><*><optimization>off
- <*><debug><optimization>off
- ;
-
- assert_equal_sets [ select-properties gcc debug my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <define>DEBUG <inlining>on <optimization>off ;
-
- assert_equal_sets [ select-properties gcc release my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <inlining>on ;
-
- assert_equal_sets [ select-properties msvc debug my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <define>DEBUG <inlining>off <optimization>off ;
-
- assert_equal_sets [ select-properties msvc release my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <inlining>on <optimization>speed ;
-}
-
-
-# ungrist-properties
-feature TEST_FEATURE1 : a b ;
-feature TEST_FEATURE2 : c d ;
-assert_equal [ ungrist-properties <TEST_FEATURE1>a <TEST_FEATURE2>c ]
- : TEST_FEATURE1-a TEST_FEATURE2-c ;
-
-
-# fixup-path-properties
-{
- local RELATIVE_SUBDIR = foobar ;
- local gPATH_FEATURES = <include> ;
- assert_equal [ fixup-path-properties <a>b <include>.. <c>d ]
- : <include>foobar$(SLASH).. <a>b <c>d ;
-}
-# multiply-property-sets
-assert_equal [ multiply-property-sets <b>1 <a>2/3 <c>4/5 ]
- : <a>2/<b>1/<c>4 <a>2/<b>1/<c>5 <a>3/<b>1/<c>4 <a>3/<b>1/<c>5 ;
-
-# make-path-property-sets
-{
- local gUNGRISTED(<a>) = a ;
- local gUNGRISTED(<c>) = c ;
- local gUNGRISTED(<e>) = e ;
- local gUNGRISTED(<g>) = g ;
- local gUNGRISTED(<i>) = i ;
- assert_equal [ make-path-property-sets foo$(SLASH)bar : <a>b <c>d : <e>f$(SLASH)<g>h <i>j ]
- : foo$(SLASH)bar$(SLASH)e-f$(SLASH)g-h$(SLASH)<a>b$(SLASH)<c>d$(SLASH)<e>f$(SLASH)<g>h foo$(SLASH)bar$(SLASH)i-j$(SLASH)<a>b$(SLASH)<c>d$(SLASH)<i>j ;
- assert_equal [ make-path-property-sets foo$(SLASH)bar : <a>b <c>d : ]
- : foo$(SLASH)bar$(SLASH)<a>b$(SLASH)<c>d ;
-}
-
-
-# split-path-at-grist
-assert_equal
- [ split-path-at-grist <a>b$(SLASH)c$(SLASH)<d>e$(SLASH)<f>g$(SLASH)h$(SLASH)i ]
- : <a>b$(SLASH)c <d>e <f>g$(SLASH)h$(SLASH)i ;
-assert_equal
- [ split-path-at-grist b$(SLASH)c$(SLASH)<d>e$(SLASH)<f>g$(SLASH)h$(SLASH)i ]
- : b$(SLASH)c <d>e <f>g$(SLASH)h$(SLASH)i ;
-if $(NT)
-{
- assert_equal
- [ split-path-at-grist b\\c\\<include>e:\\f\\g\\<h>i ]
- : b\\c <include>e:\\f\\g <h>i ;
-}
-# directory-of
-assert_equal [ directory-of a$(SLASH)b c d$(SLASH)e$(SLASH)f ] : a . d$(SLASH)e ;
-
-# top-relative-tokens
-{
- local SUBDIR_TOKENS = a b c ;
- assert_equal [ top-relative-tokens ..$(SLASH)d$(SLASH)e ] : a b d e ;
-}
-
-# flags
-{
- local gBUILD_PROPERTIES = <a>b <c>d <e>f ;
- local FLAGS1 FLAGS2 FLAGS3 ;
- flags toolset FLAGS1 <a>b/<c>d <a>b/<e>f <x>y <a>/<c> <e> : foobar ;
- assert_equal $(FLAGS1) : foobar b d f ;
- flags toolset FLAGS2 <a> : foobar ;
- assert_equal $(FLAGS2) : b ;
- flags toolset FLAGS1 <a>b/<c>d <a>b/<e>f : foobar ;
- assert_equal $(FLAGS1) : foobar b d f foobar ;
-}
-
-# get-BUILD
-{
- local DEFAULT_BUILD = a ;
- local BUILD = b ;
- assert_equal [ get-BUILD c <d>e ] : b ;
- BUILD = ;
- assert_equal [ get-BUILD c <d>e ] : c <d>e ;
- assert_equal [ get-BUILD ] : a ;
- assert_equal [ get-BUILD <d>e ] : <d>e a ;
- BUILD = <f>g ;
- assert_equal [ get-BUILD c <d>e ] : <f>g a ;
-}
-
-# strip-initial
-assert_equal [ strip-initial a b c : a b c d e f g ] : d e f g ;
-assert_equal [ strip-initial a b c : a b d e f g ] : a b d e f g ;
-assert_equal [ strip-initial a b c : b d e f g ] : b d e f g ;
-assert_equal [ strip-initial a b c : ] : ;
-
-# simplify-path-tokens
-{
- local $(gTOP)_TOKENS = .. .. .. ;
- local gINVOCATION_SUBDIR_TOKENS = d e ;
- assert_equal [ simplify-path-tokens a b . c .. .. d e ] : a d e ;
- assert_equal [ simplify-path-tokens a b .. .. .. d e ] : .. d e ;
- assert_equal [ simplify-path-tokens .. .. d e : xxx ] : .. .. d e ;
- assert_equal [ simplify-path-tokens a b .. .. : xxx ] : xxx ;
- $(gTOP)_TOKENS = .. .. ;
- assert_equal [ simplify-path-tokens .. .. d e : xxx ] : xxx ;
- assert_equal [ simplify-path-tokens .. .. d e f g : xxx ] : f g ;
-}
diff --git a/tools/build/v2/test/unused.py b/tools/build/v2/test/unused.py
index 9db2380cd1..b44320c52e 100644
--- a/tools/build/v2/test/unused.py
+++ b/tools/build/v2/test/unused.py
@@ -17,11 +17,9 @@ t.run_build_system()
# The second invocation should do nothing, and produce no warning. The previous
# invocation might have printed executed actions and other things, so it is not
# easy to check if warning was issued or not.
-t.run_build_system()
-t.fail_test(find(t.stdout(), "warning: Unused source { b.X } in main target ./a") == -1)
+t.run_build_system(stdout="")
-t.run_build_system("-sGENERATE_ONLY_UNUSABLE=1")
-t.fail_test(find(t.stdout(), "warning: Unused source { b.X } in main target ./a") == -1)
+t.run_build_system("-sGENERATE_ONLY_UNUSABLE=1", stdout="")
# Now check that even if main target generates nothing, its usage requirements
# are still propagated to dependants.
diff --git a/tools/build/v2/test/unused/jamroot.jam b/tools/build/v2/test/unused/jamroot.jam
index 75832afd20..bc97c2b197 100644
--- a/tools/build/v2/test/unused/jamroot.jam
+++ b/tools/build/v2/test/unused/jamroot.jam
@@ -10,6 +10,7 @@ import virtual-target ;
import "class" : new ;
import modules ;
import targets ;
+import project ;
type.register X : x ;
@@ -21,21 +22,23 @@ class test-target-class : basic-target
basic-target.__init__ $(name) : $(project) ;
}
- rule construct ( source-targets * : property-set )
+ rule construct ( name : source-targets * : property-set )
{
if [ modules.peek : GENERATE_NOTHING ]
{
- return ;
+ return [ property-set.empty ] ;
}
else if [ modules.peek : GENERATE_ONLY_UNUSABLE ]
{
- return [ virtual-target.from-file b.x : $(self.project) ]
+ return [ property-set.empty ]
+ [ virtual-target.from-file b.x : . : $(self.project) ]
;
}
else
{
- return [ virtual-target.from-file b.x : $(self.project) ]
- [ virtual-target.from-file b.cpp : $(self.project) ]
+ return [ property-set.empty ]
+ [ virtual-target.from-file b.x : . : $(self.project) ]
+ [ virtual-target.from-file b.cpp : . : $(self.project) ]
;
}
}
@@ -48,7 +51,7 @@ class test-target-class : basic-target
rule make-b-main-target
{
- local project = [ CALLER_MODULE ] ;
+ local project = [ project.current ] ;
targets.main-target-alternative
[ new test-target-class b : $(project) ] ;
diff --git a/tools/build/v2/test/v1-testing/a.cpp b/tools/build/v2/test/v1-testing/a.cpp
deleted file mode 100644
index 8da76c54ec..0000000000
--- a/tools/build/v2/test/v1-testing/a.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright David Abrahams 2003-2004. Distributed under the Boost
-// Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-
-void foo() {}
diff --git a/tools/build/v2/test/v1-testing/b.cpp b/tools/build/v2/test/v1-testing/b.cpp
deleted file mode 100644
index 26e752aa5e..0000000000
--- a/tools/build/v2/test/v1-testing/b.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright David Abrahams 2002.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-#error this does not compile.
diff --git a/tools/build/v2/test/v1-testing/boost-build.jam b/tools/build/v2/test/v1-testing/boost-build.jam
deleted file mode 100644
index d9e748ec26..0000000000
--- a/tools/build/v2/test/v1-testing/boost-build.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-TOOLS = gcc ;
-boost-build ../.. ;
diff --git a/tools/build/v2/test/v1-testing/c.cpp b/tools/build/v2/test/v1-testing/c.cpp
deleted file mode 100644
index 42f5d9c58c..0000000000
--- a/tools/build/v2/test/v1-testing/c.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright David Abrahams 2002.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-#include <iostream>
-
-#ifndef RESULTCODE
-# define RESULTCODE 0
-#endif
-
-int main()
-{
- std::cout << "returning result: " << RESULTCODE << std::endl;
- return RESULTCODE;
-}
-
diff --git a/tools/build/v2/test/v1-testing/jamfile.jam b/tools/build/v2/test/v1-testing/jamfile.jam
deleted file mode 100644
index 011940f8ae..0000000000
--- a/tools/build/v2/test/v1-testing/jamfile.jam
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2002, 2003 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import testing ;
-
-# A number of tests which should succeed
-compile a.cpp ;
-compile-fail b.cpp ;
-link-fail a.cpp : : link-no ;
-link c.cpp : : link-yes ;
-run c.cpp : : : : run-yes ;
-run-fail c.cpp : : : <define>RESULTCODE=1 : run-no ;
-
-# some tests which should fail
-
-compile-fail a.cpp : : fail-compile-no ;
-compile b.cpp : : fail-compile-yes ;
-link a.cpp : : fail-link-yes ;
-link-fail c.cpp : : fail-link-no ;
-run-fail c.cpp : : : : fail-run-no ;
-run c.cpp : : : <define>RESULTCODE=1 : fail-run-yes ;
-
-# Make sure we still fail if a dependency of an expected-failure test
-# fails.
-link-fail b.cpp : : fail-link-no-dependency ;
diff --git a/tools/build/v2/test/v1_testing.py b/tools/build/v2/test/v1_testing.py
deleted file mode 100644
index 524775fac4..0000000000
--- a/tools/build/v2/test/v1_testing.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Dave Abrahams
-# Copyright 2004 Vladimir Prus
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import BoostBuild
-import os
-from string import strip
-import re
-import time
-
-def match_re(actual,expected):
- return re.match(expected,actual,re.DOTALL) != None
-
-t = BoostBuild.Tester(match = match_re, boost_build_path = os.path.join(os.getcwd(), ".."))
-t.set_tree('v1_testing')
-
-os.environ['TOOLS'] = 'gcc'
-os.environ['NOARSCAN'] = '1'
-
-# 1) No existing bin directories. Both build and test ran fine. As
-# expected, the residue files were a bit different: There was no
-# path_test.success, and path_test.test contained the word "passed"
-# instead of the path to the .cpp file. I've haven't looked yet to
-# see if the lack of the path is a problem for reporting, but
-# hopefully the information is trivially available somewhere else.
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- ['bin/compile.test/gcc/debug/runtime-link-dynamic/compile.test'
- , 'bin/nocompile.test/gcc/debug/runtime-link-dynamic/nocompile.test'
- , 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-
-# 2) Missing source file for the library build. path_test.test was
-# deleted, so the reporting programs would know that failure
-# occurred. The stdout messages also indicated what had
-# happened. Excellent!
-t.rename('lib.cpp', 'lib.cpp.bak')
-t.run_build_system(arguments = 'test', status = 1)
-t.expect_removal(
- ['bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-# 3) Missing file restored. Worked fine; path_test.test was recreated,
-# no other files were touched.
-t.rename('lib.cpp.bak', 'lib.cpp')
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- [ 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
- # I didn't add a test for 'no other files were touched', because
- # it's a little complicated. There is an expect_nothing_more()
- # function, but we actually need to spell out a lot more than
- # what we currently have to do that.
-
-# 4) Introduced error into one of the library files, causing a library build
-# compile to fail. path_test.test was deleted, so the reporting programs
-# would know that failure occurred. Excellent! This is the case that has
-# caused regression testing to report the wrong results in the past, so it
-# was good news to see it working correctly now. We probably should figure
-# out some other test cases just to be sure it is working for full coverage.
-t.rename('lib.cpp', 'lib.cpp.bak')
-t.rename('lib-err.cpp', 'lib.cpp')
-t.touch('lib.cpp')
-t.run_build_system(arguments = 'test', status=1)
-t.expect_removal(
- ['bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-# 5) Fixed the error in the library file. The library build then worked, and
-# path_test.exe was relinked, without first recompiling path_test.obj. Test was
-# rerun. Exactly the right behavior!
-t.rename('lib.cpp.bak', 'lib.cpp')
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- [ 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-t.cleanup()
-print 'testing complete'
diff --git a/tools/build/v2/test/v1_testing/Jamrules b/tools/build/v2/test/v1_testing/Jamrules
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tools/build/v2/test/v1_testing/Jamrules
+++ /dev/null
diff --git a/tools/build/v2/test/v1_testing/boost-build.jam b/tools/build/v2/test/v1_testing/boost-build.jam
deleted file mode 100644
index d9e748ec26..0000000000
--- a/tools/build/v2/test/v1_testing/boost-build.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-TOOLS = gcc ;
-boost-build ../.. ;
diff --git a/tools/build/v2/test/v1_testing/foo.cpp b/tools/build/v2/test/v1_testing/foo.cpp
deleted file mode 100644
index 6741a59439..0000000000
--- a/tools/build/v2/test/v1_testing/foo.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright David Abrahams 2002.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#if NOCOMPILE
-1 = 1;
-#endif
-
-void lib();
-
-void f()
-{
- lib();
-}
-
-#ifndef NOLINK
-int main()
-{
-}
-#endif
-
diff --git a/tools/build/v2/test/v1_testing/jamfile.jam b/tools/build/v2/test/v1_testing/jamfile.jam
deleted file mode 100644
index 2e0bedac7c..0000000000
--- a/tools/build/v2/test/v1_testing/jamfile.jam
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2002, 2003 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-TOOLS = $(TOOLS[1]) ;
-project-root ;
-
-# bring in rules for testing
-import testing ;
-
-lib mylib : lib.cpp ;
-
-compile foo.cpp : : compile ;
-compile-fail foo.cpp : <define>NOCOMPILE : nocompile ;
-
-link foo.cpp <lib>mylib : : link ;
-link-fail foo.cpp <lib>mylib : <define>NOLINK : nolink ;
-
-run foo.cpp <lib>mylib
- : # args
- : # input-files
- : <define>RUN
- : run ;
diff --git a/tools/build/v2/test/v1_testing/jamroot.jam b/tools/build/v2/test/v1_testing/jamroot.jam
deleted file mode 100644
index fe69424588..0000000000
--- a/tools/build/v2/test/v1_testing/jamroot.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2002 Dave Abrahams
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-# just label the project root
diff --git a/tools/build/v2/test/v1_testing/lib-err.cpp b/tools/build/v2/test/v1_testing/lib-err.cpp
deleted file mode 100644
index 060fd73e56..0000000000
--- a/tools/build/v2/test/v1_testing/lib-err.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright David Abrahams 2002.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-3 = 4;
-void lib() {}
diff --git a/tools/build/v2/test/v1_testing/lib.cpp b/tools/build/v2/test/v1_testing/lib.cpp
deleted file mode 100644
index 1472b96ad5..0000000000
--- a/tools/build/v2/test/v1_testing/lib.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright David Abrahams 2002.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-void lib() {}
diff --git a/tools/build/v2/tools/auto-index.jam b/tools/build/v2/tools/auto-index.jam
index ebbf344eba..5c5c1d06cf 100644
--- a/tools/build/v2/tools/auto-index.jam
+++ b/tools/build/v2/tools/auto-index.jam
@@ -11,8 +11,8 @@ feature.feature auto-index : off "on" ;
feature.feature auto-index-internal : off "on" ;
feature.feature auto-index-verbose : off "on" ;
feature.feature auto-index-no-duplicates : off "on" ;
-feature.feature auto-index-script : : free ;
-feature.feature auto-index-prefix : : free ;
+feature.feature auto-index-script : : free path ;
+feature.feature auto-index-prefix : : free path ;
feature.feature auto-index-type : : free ;
feature.feature auto-index-section-names : "on" off ;
diff --git a/tools/build/v2/tools/boostbook.jam b/tools/build/v2/tools/boostbook.jam
index 3a5964c627..3ab0debdb0 100644
--- a/tools/build/v2/tools/boostbook.jam
+++ b/tools/build/v2/tools/boostbook.jam
@@ -336,6 +336,9 @@ rule find-tools ( docbook-xsl-dir ? : docbook-dtd-dir ? : boostbook-dir ? )
# Ubuntu Linux
docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet : nwalsh ] ;
docbook-dtd-dir ?= [ path.glob /usr/share/xml/docbook/schema/dtd : $(dtd-versions) ] ;
+
+ # SUSE
+ docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet/nwalsh : current ] ;
}
if $(docbook-xsl-dir)
diff --git a/tools/build/v2/tools/builtin.py b/tools/build/v2/tools/builtin.py
index 31a7bffeef..5b28a0aa78 100644
--- a/tools/build/v2/tools/builtin.py
+++ b/tools/build/v2/tools/builtin.py
@@ -144,11 +144,20 @@ def register_globals ():
feature.feature ('threading', ['single', 'multi'], ['propagated'])
feature.feature ('rtti', ['on', 'off'], ['propagated'])
feature.feature ('exception-handling', ['on', 'off'], ['propagated'])
+
+ # Whether there is support for asynchronous EH (e.g. catching SEGVs).
+ feature.feature ('asynch-exceptions', ['on', 'off'], ['propagated'])
+
+ # Whether all extern "C" functions are considered nothrow by default.
+ feature.feature ('extern-c-nothrow', ['off', 'on'], ['propagated'])
+
feature.feature ('debug-symbols', ['on', 'off'], ['propagated'])
feature.feature ('define', [], ['free'])
+ feature.feature ('undef', [], ['free'])
feature.feature ('include', [], ['free', 'path']) #order-sensitive
feature.feature ('cflags', [], ['free'])
feature.feature ('cxxflags', [], ['free'])
+ feature.feature ('asmflags', [], ['free'])
feature.feature ('linkflags', [], ['free'])
feature.feature ('archiveflags', [], ['free'])
feature.feature ('version', [], ['free'])
@@ -309,10 +318,6 @@ def register_globals ():
variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
'<runtime-debugging>off', '<define>NDEBUG'])
variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
-
- type.register ('H', ['h'])
- type.register ('HPP', ['hpp'], 'H')
- type.register ('C', ['c'])
reset ()
@@ -348,8 +353,11 @@ class SearchedLibTarget (virtual_target.AbstractFileTarget):
class CScanner (scanner.Scanner):
def __init__ (self, includes):
scanner.Scanner.__init__ (self)
-
- self.includes_ = includes
+
+ self.includes_ = []
+
+ for i in includes:
+ self.includes_.extend(i.split("&&"))
def pattern (self):
return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
@@ -399,7 +407,7 @@ class LibGenerator (generators.Generator):
SHARED_LIB.
"""
- def __init__(self, id = 'LibGenerator', composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
+ def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
def run(self, project, name, prop_set, sources):
@@ -432,7 +440,9 @@ class LibGenerator (generators.Generator):
def viable_source_types(self):
return ['*']
-generators.register(LibGenerator())
+generators.register(LibGenerator("builtin.lib-generator"))
+
+generators.override("builtin.prebuilt", "builtin.lib-generator")
def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
"""The implementation of the 'lib' rule. Beyond standard syntax that rule allows
@@ -508,22 +518,19 @@ class SearchedLibGenerator (generators.Generator):
generators.register (SearchedLibGenerator ())
-### class prebuilt-lib-generator : generator
-### {
-### rule __init__ ( * : * )
-### {
-### generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
-### }
-###
-### rule run ( project name ? : prop_set : sources * : multiple ? )
-### {
-### local f = [ $(prop_set).get <file> ] ;
-### return $(f) $(sources) ;
-### }
-### }
-###
-### generators.register
-### [ new prebuilt-lib-generator builtin.prebuilt : : LIB : <file> ] ;
+class PrebuiltLibGenerator(generators.Generator):
+
+ def __init__(self, id, composing, source_types, target_types_and_names, requirements):
+ generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
+
+ def run(self, project, name, properties, sources):
+ f = properties.get("file")
+ return f + sources
+
+generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
+ ["LIB"], ["<file>"]))
+
+generators.override("builtin.prebuilt", "builtin.lib-generator")
class CompileAction (virtual_target.Action):
@@ -565,9 +572,8 @@ class LinkingGenerator (generators.Generator):
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
def run (self, project, name, prop_set, sources):
-
- lib_sources = prop_set.get('<library>')
- sources.extend(lib_sources)
+
+ sources.extend(prop_set.get('<library>'))
# Add <library-path> properties for all searched libraries
extra = []
@@ -576,38 +582,41 @@ class LinkingGenerator (generators.Generator):
search = s.search()
extra.extend(property.Property('<library-path>', sp) for sp in search)
- orig_xdll_path = []
-
- if prop_set.get('<hardcode-dll-paths>') == ['true'] \
- and type.is_derived(self.target_types_ [0], 'EXE'):
- xdll_path = prop_set.get('<xdll-path>')
- orig_xdll_path = [ replace_grist(x, '<dll-path>') for x in xdll_path ]
- # It's possible that we have libraries in sources which did not came
- # from 'lib' target. For example, libraries which are specified
- # just as filenames as sources. We don't have xdll-path properties
- # for such target, but still need to add proper dll-path properties.
- for s in sources:
+ # It's possible that we have libraries in sources which did not came
+ # from 'lib' target. For example, libraries which are specified
+ # just as filenames as sources. We don't have xdll-path properties
+ # for such target, but still need to add proper dll-path properties.
+ extra_xdll_path = []
+ for s in sources:
if type.is_derived (s.type (), 'SHARED_LIB') and not s.action ():
# Unfortunately, we don't have a good way to find the path
# to a file, so use this nasty approach.
p = s.project()
- location = path.root(s.name(), p.get('source-location'))
- xdll_path.append(path.parent(location))
-
- extra.extend(property.Property('<dll-path>', sp) for sp in xdll_path)
+ location = path.root(s.name(), p.get('source-location')[0])
+ extra_xdll_path.append(os.path.dirname(location))
+
+ # Hardcode DLL paths only when linking executables.
+ # Pros: do not need to relink libraries when installing.
+ # Cons: "standalone" libraries (plugins, python extensions) can not
+ # hardcode paths to dependent libraries.
+ if prop_set.get('<hardcode-dll-paths>') == ['true'] \
+ and type.is_derived(self.target_types_ [0], 'EXE'):
+ xdll_path = prop_set.get('<xdll-path>')
+ extra.extend(property.Property('<dll-path>', sp) \
+ for sp in extra_xdll_path)
+ extra.extend(property.Property('<dll-path>', sp) \
+ for sp in xdll_path)
if extra:
- prop_set = prop_set.add_raw (extra)
-
+ prop_set = prop_set.add_raw (extra)
result = generators.Generator.run(self, project, name, prop_set, sources)
-
+
if result:
ur = self.extra_usage_requirements(result, prop_set)
- ur = ur.add(property_set.create(orig_xdll_path))
+ ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path]))
else:
return None
-
- return(ur, result)
+ return (ur, result)
def extra_usage_requirements (self, created_targets, prop_set):
@@ -696,20 +705,18 @@ class ArchiveGenerator (generators.Generator):
return result
-### rule register-archiver ( id composing ? : source_types + : target_types + :
-### requirements * )
-### {
-### local g = [ new ArchiveGenerator $(id) $(composing) : $(source_types)
-### : $(target_types) : $(requirements) ] ;
-### generators.register $(g) ;
-### }
-###
-###
-### IMPORT $(__name__) : register-linker register-archiver
-### : : generators.register-linker generators.register-archiver ;
-###
-###
-###
+
+def register_archiver(id, source_types, target_types, requirements):
+ g = ArchiveGenerator(id, True, source_types, target_types, requirements)
+ generators.register(g)
+
+class DummyGenerator(generators.Generator):
+ """Generator that accepts everything and produces nothing. Useful as a general
+ fallback for toolset-specific actions like PCH generation.
+ """
+ def run (self, project, name, prop_set, sources):
+ return (property_set.empty(), [])
+
get_manager().projects().add_rule("variant", variant)
diff --git a/tools/build/v2/tools/cast.jam b/tools/build/v2/tools/cast.jam
index 6c84922f1f..211ce63296 100644
--- a/tools/build/v2/tools/cast.jam
+++ b/tools/build/v2/tools/cast.jam
@@ -11,7 +11,7 @@
#
# exe main : main.cpp [ cast _ moccable-cpp : widget.cpp ] ;
#
-# Boost.Build will assing target type CPP to both main.cpp and widget.cpp. Then,
+# Boost.Build will assign target type CPP to both main.cpp and widget.cpp. Then,
# the cast rule will change target type of widget.cpp to MOCCABLE-CPP, and Qt
# support will run the MOC tool as part of the build process.
#
diff --git a/tools/build/v2/tools/common.jam b/tools/build/v2/tools/common.jam
index df914d9d46..53e91b428f 100644
--- a/tools/build/v2/tools/common.jam
+++ b/tools/build/v2/tools/common.jam
@@ -334,7 +334,7 @@ rule get-absolute-tool-path ( command )
# first path found. Otherwise, returns an empty string. If 'path-last' is
# specified, PATH is searched after 'additional-paths'.
#
-local rule find-tool ( name : additional-paths * : path-last ? )
+rule find-tool ( name : additional-paths * : path-last ? )
{
local path = [ path.programs-path ] ;
local match = [ path.glob $(path) : $(name) $(name).exe ] ;
@@ -961,25 +961,22 @@ rule __test__ ( )
{
import assert ;
- local nl = "
-" ;
-
local save-os = [ modules.peek os : .name ] ;
modules.poke os : .name : LINUX ;
- assert.result "PATH=\"foo:bar:baz\"$(nl)export PATH$(nl)"
+ assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
: path-variable-setting-command PATH : foo bar baz ;
- assert.result "PATH=\"foo:bar:$PATH\"$(nl)export PATH$(nl)"
+ assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
: prepend-path-variable-command PATH : foo bar ;
modules.poke os : .name : NT ;
- assert.result "set PATH=foo;bar;baz$(nl)"
+ assert.result "set PATH=foo;bar;baz\n"
: path-variable-setting-command PATH : foo bar baz ;
- assert.result "set PATH=foo;bar;%PATH%$(nl)"
+ assert.result "set PATH=foo;bar;%PATH%\n"
: prepend-path-variable-command PATH : foo bar ;
modules.poke os : .name : $(save-os) ;
diff --git a/tools/build/v2/tools/common.py b/tools/build/v2/tools/common.py
index 612745b81f..3eb0f7d3f1 100644
--- a/tools/build/v2/tools/common.py
+++ b/tools/build/v2/tools/common.py
@@ -53,7 +53,7 @@ def reset ():
if OS == "NT":
# On Windows the case and capitalization of PATH is not always predictable, so
# let's find out what variable name was really set.
- for n in sys.environ:
+ for n in os.environ:
if n.lower() == "path":
__executable_path_variable = n
break
@@ -99,7 +99,7 @@ class Configurations(object):
def __init__(self):
self.used_ = set()
self.all_ = set()
- self.params = {}
+ self.params_ = {}
def register(self, id):
"""
@@ -113,7 +113,7 @@ class Configurations(object):
errors.error("common: the configuration '$(id)' is in use")
if id not in self.all_:
- self.all_ += [id]
+ self.all_.add(id)
# Indicate that a new configuration has been added.
return True
@@ -133,7 +133,7 @@ class Configurations(object):
errors.error("common: the configuration '$(id)' is not known")
if id not in self.used_:
- self.used_ += [id]
+ self.used_.add(id)
# indicate that the configuration has been marked as 'used'
return True
@@ -150,7 +150,7 @@ class Configurations(object):
def get(self, id, param):
""" Returns the value of a configuration parameter. """
- self.params_.getdefault(param, {}).getdefault(id, None)
+ return self.params_.get(param, {}).get(id)
def set (self, id, param, value):
""" Sets the value of a configuration parameter. """
@@ -294,6 +294,8 @@ def get_invocation_command_nodefault(
#print "warning: initialized from" [ errors.nearest-user-location ] ;
else:
command = check_tool(user_provided_command)
+ assert(isinstance(command, list))
+ command=' '.join(command)
if not command and __debug_configuration:
print "warning: toolset", toolset, "initialization:"
print "warning: can't find user-provided command", user_provided_command
@@ -347,7 +349,9 @@ def get_absolute_tool_path(command):
programs = path.programs_path()
m = path.glob(programs, [command, command + '.exe' ])
if not len(m):
- print "Could not find:", command, "in", programs
+ if __debug_configuration:
+ print "Could not find:", command, "in", programs
+ return None
return os.path.dirname(m[0])
# ported from trunk@47174
diff --git a/tools/build/v2/tools/cray.jam b/tools/build/v2/tools/cray.jam
new file mode 100644
index 0000000000..1d5271e972
--- /dev/null
+++ b/tools/build/v2/tools/cray.jam
@@ -0,0 +1,112 @@
+# Copyright 2001 David Abrahams.
+# Copyright 2004, 2005 Markus Schoepflin.
+# Copyright 2011, John Maddock
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+#
+# Cray C++ Compiler
+# See http://docs.cray.com/books/S-2179-50/html-S-2179-50/S-2179-50-toc.html
+#
+
+import feature generators common ;
+import toolset : flags ;
+
+feature.extend toolset : cray ;
+
+# Inherit from Unix toolset to get library ordering magic.
+toolset.inherit cray : unix ;
+
+generators.override cray.prebuilt : builtin.lib-generator ;
+generators.override cray.prebuilt : builtin.prebuilt ;
+generators.override cray.searched-lib-generator : searched-lib-generator ;
+
+
+rule init ( version ? : command * : options * )
+{
+ local condition = [ common.check-init-parameters cray : version $(version) ] ;
+
+ local command = [ common.get-invocation-command cray : CC : $(command) ] ;
+
+ if $(command)
+ {
+ local root = [ common.get-absolute-tool-path $(command[-1]) ] ;
+
+ if $(root)
+ {
+ flags cray .root $(condition) : "\"$(root)\"/" ;
+ }
+ }
+ # If we can't find 'CC' anyway, at least show 'CC' in the commands
+ command ?= CC ;
+
+ common.handle-options cray : $(condition) : $(command) : $(options) ;
+}
+
+generators.register-c-compiler cray.compile.c++ : CPP : OBJ : <toolset>cray ;
+generators.register-c-compiler cray.compile.c : C : OBJ : <toolset>cray ;
+
+
+
+# No static linking as far as I can tell.
+# flags cxx LINKFLAGS <runtime-link>static : -bstatic ;
+flags cray.compile OPTIONS <debug-symbols>on : -Gn ;
+flags cray.link OPTIONS <debug-symbols>on : -Gn ;
+
+flags cray.compile OPTIONS <optimization>off : -O0 ;
+flags cray.compile OPTIONS <optimization>speed : -O3 ;
+flags cray.compile OPTIONS <optimization>space : -O1 ;
+
+flags cray.compile OPTIONS <cflags> ;
+flags cray.compile.c++ OPTIONS <cxxflags> ;
+flags cray.compile DEFINES <define> ;
+flags cray.compile INCLUDES <include> ;
+flags cray.link OPTIONS <linkflags> ;
+
+flags cray.link LIBPATH <library-path> ;
+flags cray.link LIBRARIES <library-file> ;
+flags cray.link FINDLIBS-ST <find-static-library> ;
+flags cray.link FINDLIBS-SA <find-shared-library> ;
+
+actions link bind LIBRARIES
+{
+ $(CONFIG_COMMAND) $(OPTIONS) -o "$(<)" -L$(LIBPATH) "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA)
+}
+
+# When creating dynamic libraries, we don't want to be warned about unresolved
+# symbols, therefore all unresolved symbols are marked as expected by
+# '-expect_unresolved *'. This also mirrors the behaviour of the GNU tool
+# chain.
+
+actions link.dll bind LIBRARIES
+{
+ $(CONFIG_COMMAND) -shared $(OPTIONS) -o "$(<[1])" -L$(LIBPATH) "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA)
+}
+
+
+# Note: Relaxed ANSI mode (-std) is used for compilation because in strict ANSI
+# C89 mode (-std1) the compiler doesn't accept C++ comments in C files. As -std
+# is the default, no special flag is needed.
+actions compile.c
+{
+ $(.root:E=)cc -c $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -o "$(<)" "$(>)"
+}
+
+# Note: The compiler is forced to compile the files as C++ (-x cxx) because
+# otherwise it will silently ignore files with no file extension.
+#
+# Note: We deliberately don't suppress any warnings on the compiler command
+# line, the user can always do this in a customized toolset later on.
+
+actions compile.c++
+{
+ $(CONFIG_COMMAND) -c -h gnu $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -o "$(<)" "$(>)"
+}
+
+# Always create archive from scratch. See the gcc toolet for rationale.
+RM = [ common.rm-command ] ;
+actions together piecemeal archive
+{
+ $(RM) "$(<)"
+ ar rc $(<) $(>)
+}
diff --git a/tools/build/v2/tools/darwin.jam b/tools/build/v2/tools/darwin.jam
index 283dface94..dd6eacb114 100644
--- a/tools/build/v2/tools/darwin.jam
+++ b/tools/build/v2/tools/darwin.jam
@@ -231,7 +231,7 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
{
if $(.debug-configuration)
{
- ECHO notice: available sdk for $(condition)/<macosx-version>$(version-feature) at $(sdk) ;
+ ECHO notice: available sdk for $(condition)/<macosx-version>$(version-feature) at $(root) ;
}
# Add the version to the features for specifying them.
@@ -247,9 +247,9 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
# Set the flags the version needs to compile with, first
# generic options.
flags darwin.compile OPTIONS $(condition)/<macosx-version>$(version-feature)
- : -isysroot $(sdk) ;
+ : -isysroot $(root) ;
flags darwin.link OPTIONS $(condition)/<macosx-version>$(version-feature)
- : -isysroot $(sdk) ;
+ : -isysroot $(root) ;
# Then device variation options.
switch $(version[1])
@@ -287,13 +287,28 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
}
}
- return $(version-feature) ;
+ if $(version[3]) > 0
+ {
+ # We have a minor version of an SDK. We want to set up
+ # previous minor versions, plus the current minor version.
+ # So we recurse to set up the previous minor versions, up to
+ # the current version.
+ local minor-minus-1 = [ CALC $(version[3]) - 1 ] ;
+ return
+ [ init-sdk $(condition) : $(root)
+ : $(version[1-2]) $(minor-minus-1) : [ version-to-feature $(version[1-2]) $(minor-minus-1) ] ]
+ $(version-feature) ;
+ }
+ else
+ {
+ return $(version-feature) ;
+ }
}
else if $(version[4])
{
# We have a patch version of an SDK. We want to set up
# both the specific patch version, and the minor version.
- # So we recurse to set up the minor version. Plus the minor version.
+ # So we recurse to set up the patch version. Plus the minor version.
return
[ init-sdk $(condition) : $(root)
: $(version[1-3]) : [ version-to-feature $(version[1-3]) ] ]
@@ -498,7 +513,7 @@ flags darwin.link OPTIONS <optimization>space : -Wl,-dead_strip -no_dead_strip_i
flags darwin.compile OPTIONS <link>shared : -dynamic ;
# Misc options.
-flags darwin.compile OPTIONS : -no-cpp-precomp -gdwarf-2 -fexceptions ;
+flags darwin.compile OPTIONS : -gdwarf-2 -fexceptions ;
#~ flags darwin.link OPTIONS : -fexceptions ;
# Add the framework names to use.
diff --git a/tools/build/v2/tools/docutils.jam b/tools/build/v2/tools/docutils.jam
index bf0616174b..fc775b6fc3 100644
--- a/tools/build/v2/tools/docutils.jam
+++ b/tools/build/v2/tools/docutils.jam
@@ -56,6 +56,7 @@ rule init ( docutils-dir ? : tools-dir ? )
.setup = [
common.prepend-path-variable-command PYTHONPATH
: $(.docutils-dir) $(.docutils-dir)/extras ] ;
+ RST2XXX = [ common.find-tool rst2html ] ;
}
}
diff --git a/tools/build/v2/tools/gcc.jam b/tools/build/v2/tools/gcc.jam
index f7b0da542e..ee3aae128a 100644
--- a/tools/build/v2/tools/gcc.jam
+++ b/tools/build/v2/tools/gcc.jam
@@ -446,13 +446,17 @@ rule setup-address-model ( targets * : sources * : properties * )
}
else
{
- if $(model) = 32
- {
- option = -m32 ;
- }
- else if $(model) = 64
+ local arch = [ feature.get-values architecture : $(properties) ] ;
+ if $(arch) != arm
{
- option = -m64 ;
+ if $(model) = 32
+ {
+ option = -m32 ;
+ }
+ else if $(model) = 64
+ {
+ option = -m64 ;
+ }
}
# For darwin, the model can be 32_64. darwin.jam will handle that
# on its own.
@@ -1097,9 +1101,10 @@ local rule cpu-flags ( toolset variable : architecture : instruction-set + : val
#
# x86 and compatible
# The 'native' option appeared in gcc 4.2 so we cannot safely use it
-# as default. Use conservative i386 instead.
+# as default. Use conservative i386 instead for 32-bit.
+toolset.flags gcc OPTIONS <architecture>x86/<address-model>32/<instruction-set> : -march=i386 ;
cpu-flags gcc OPTIONS : x86 : native : -march=native ;
-cpu-flags gcc OPTIONS : x86 : i386 : -march=i386 : default ;
+cpu-flags gcc OPTIONS : x86 : i386 : -march=i386 ;
cpu-flags gcc OPTIONS : x86 : i486 : -march=i486 ;
cpu-flags gcc OPTIONS : x86 : i586 : -march=i586 ;
cpu-flags gcc OPTIONS : x86 : i686 : -march=i686 ;
diff --git a/tools/build/v2/tools/gcc.py b/tools/build/v2/tools/gcc.py
index 2a3e675ef1..b0aba1d293 100644
--- a/tools/build/v2/tools/gcc.py
+++ b/tools/build/v2/tools/gcc.py
@@ -23,13 +23,16 @@ import re
import bjam
from b2.tools import unix, common, rc, pch, builtin
-from b2.build import feature, type, toolset, generators
+from b2.build import feature, type, toolset, generators, property_set
+from b2.build.property import Property
from b2.util.utility import os_name, on_windows
from b2.manager import get_manager
from b2.build.generators import Generator
from b2.build.toolset import flags
from b2.util.utility import to_seq
+
+
__debug = None
def debug():
@@ -222,12 +225,12 @@ class GccPchGenerator(pch.PchGenerator):
# Find the header in sources. Ignore any CPP sources.
header = None
for s in sources:
- if type.is_derived(s.type, 'H'):
+ if type.is_derived(s.type(), 'H'):
header = s
# Error handling: Base header file name should be the same as the base
# precompiled header name.
- header_name = header.name
+ header_name = header.name()
header_basename = os.path.basename(header_name).rsplit('.', 1)[0]
if header_basename != name:
location = project.project_module
@@ -239,14 +242,15 @@ class GccPchGenerator(pch.PchGenerator):
# return result of base class and pch-file property as usage-requirements
# FIXME: what about multiple results from generator.run?
- return (property_set.create('<pch-file>' + pch_file[0], '<cflags>-Winvalid-pch'),
+ return (property_set.create([Property('pch-file', pch_file[0]),
+ Property('cflags', '-Winvalid-pch')]),
pch_file)
# Calls the base version specifying source's name as the name of the created
# target. As result, the PCH will be named whatever.hpp.gch, and not
# whatever.gch.
def generated_targets(self, sources, prop_set, project, name = None):
- name = sources[0].name
+ name = sources[0].name()
return Generator.generated_targets(self, sources,
prop_set, project, name)
diff --git a/tools/build/v2/tools/intel-win.jam b/tools/build/v2/tools/intel-win.jam
index 691b5dce98..c9adac0d96 100644
--- a/tools/build/v2/tools/intel-win.jam
+++ b/tools/build/v2/tools/intel-win.jam
@@ -161,8 +161,8 @@ rule init ( version ? : # the compiler version
if ! $(compatibility)
{
- # If there's no backend version, assume 7.1.
- compatibility = vc7.1 ;
+ # If there's no backend version, assume 10.
+ compatibility = vc10 ;
}
local extract-version = [ MATCH ^vc(.*) : $(compatibility) ] ;
diff --git a/tools/build/v2/tools/mc.py b/tools/build/v2/tools/mc.py
new file mode 100644
index 0000000000..c194acdff7
--- /dev/null
+++ b/tools/build/v2/tools/mc.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2005 Alexey Pakhunov.
+# Copyright (c) 2011 Juraj Ivancic
+#
+# Use, modification and distribution is subject to the Boost Software
+# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
+# http://www.boost.org/LICENSE_1_0.txt)
+
+# Support for Microsoft message compiler tool.
+# Notes:
+# - there's just message compiler tool, there's no tool for
+# extracting message strings from sources
+# - This file allows to use Microsoft message compiler
+# with any toolset. In msvc.jam, there's more specific
+# message compiling action.
+
+import bjam
+
+from b2.tools import common, rc
+from b2.build import generators, type
+from b2.build.toolset import flags
+from b2.build.feature import feature
+from b2.manager import get_manager
+
+def init():
+ pass
+
+type.register('MC', ['mc'])
+
+
+# Command line options
+feature('mc-input-encoding', ['ansi', 'unicode'], ['free'])
+feature('mc-output-encoding', ['unicode', 'ansi'], ['free'])
+feature('mc-set-customer-bit', ['no', 'yes'], ['free'])
+
+flags('mc.compile', 'MCFLAGS', ['<mc-input-encoding>ansi'], ['-a'])
+flags('mc.compile', 'MCFLAGS', ['<mc-input-encoding>unicode'], ['-u'])
+flags('mc.compile', 'MCFLAGS', ['<mc-output-encoding>ansi'], '-A')
+flags('mc.compile', 'MCFLAGS', ['<mc-output-encoding>unicode'], ['-U'])
+flags('mc.compile', 'MCFLAGS', ['<mc-set-customer-bit>no'], [])
+flags('mc.compile', 'MCFLAGS', ['<mc-set-customer-bit>yes'], ['-c'])
+
+generators.register_standard('mc.compile', ['MC'], ['H', 'RC'])
+
+get_manager().engine().register_action(
+ 'mc.compile',
+ 'mc $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"')
diff --git a/tools/build/v2/tools/midl.py b/tools/build/v2/tools/midl.py
new file mode 100644
index 0000000000..45811d16bc
--- /dev/null
+++ b/tools/build/v2/tools/midl.py
@@ -0,0 +1,134 @@
+# Copyright (c) 2005 Alexey Pakhunov.
+# Copyright (c) 2011 Juraj Ivancic
+#
+# Use, modification and distribution is subject to the Boost Software
+# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
+# http://www.boost.org/LICENSE_1_0.txt)
+
+# Microsoft Interface Definition Language (MIDL) related routines
+from b2.build import scanner, type
+from b2.build.toolset import flags
+from b2.build.feature import feature
+from b2.manager import get_manager
+from b2.tools import builtin, common
+from b2.util import regex
+
+def init():
+ pass
+
+type.register('IDL', ['idl'])
+
+# A type library (.tlb) is generated by MIDL compiler and can be included
+# to resources of an application (.rc). In order to be found by a resource
+# compiler its target type should be derived from 'H' - otherwise
+# the property '<implicit-dependency>' will be ignored.
+type.register('MSTYPELIB', 'tlb', 'H')
+
+# Register scanner for MIDL files
+class MidlScanner(scanner.Scanner):
+ def __init__ (self, includes=[]):
+ scanner.Scanner.__init__(self)
+ self.includes = includes
+
+ # List of quoted strings
+ re_strings = "[ \t]*\"([^\"]*)\"([ \t]*,[ \t]*\"([^\"]*)\")*[ \t]*" ;
+
+ # 'import' and 'importlib' directives
+ self.re_import = "import" + re_strings + "[ \t]*;" ;
+ self.re_importlib = "importlib[ \t]*[(]" + re_strings + "[)][ \t]*;" ;
+
+ # C preprocessor 'include' directive
+ self.re_include_angle = "#[ \t]*include[ \t]*<(.*)>" ;
+ self.re_include_quoted = "#[ \t]*include[ \t]*\"(.*)\"" ;
+
+ def pattern():
+ # Match '#include', 'import' and 'importlib' directives
+ return "((#[ \t]*include|import(lib)?).+(<(.*)>|\"(.*)\").+)"
+
+ def process(self, target, matches, binding):
+ included_angle = regex.transform(matches, self.re_include_angle)
+ included_quoted = regex.transform(matches, self.re_include_quoted)
+ imported = regex.transform(matches, self.re_import, [1, 3])
+ imported_tlbs = regex.transform(matches, self.re_importlib, [1, 3])
+
+ # CONSIDER: the new scoping rule seem to defeat "on target" variables.
+ g = bjam.call('get-target-variable', target, 'HDRGRIST')
+ b = os.path.normalize_path(os.path.dirname(binding))
+
+ # Attach binding of including file to included targets.
+ # When target is directly created from virtual target
+ # this extra information is unnecessary. But in other
+ # cases, it allows to distinguish between two headers of the
+ # same name included from different places.
+ g2 = g + "#" + b
+
+ g = "<" + g + ">"
+ g2 = "<" + g2 + ">"
+
+ included_angle = [ g + x for x in included_angle ]
+ included_quoted = [ g + x for x in included_quoted ]
+ imported = [ g + x for x in imported ]
+ imported_tlbs = [ g + x for x in imported_tlbs ]
+
+ all = included_angle + included_quoted + imported
+
+ bjam.call('INCLUDES', [target], all)
+ bjam.call('DEPENDS', [target], imported_tlbs)
+ bjam.call('NOCARE', all + imported_tlbs)
+ engine.set_target_variable(included_angle , 'SEARCH', ungrist(self.includes))
+ engine.set_target_variable(included_quoted, 'SEARCH', b + ungrist(self.includes))
+ engine.set_target_variable(imported , 'SEARCH', b + ungrist(self.includes))
+ engine.set_target_variable(imported_tlbs , 'SEARCH', b + ungrist(self.includes))
+
+ get_manager().scanners().propagate(type.get_scanner('CPP', PropertySet(self.includes)), included_angle + included_quoted)
+ get_manager().scanners().propagate(self, imported)
+
+scanner.register(MidlScanner, 'include')
+type.set_scanner('IDL', MidlScanner)
+
+
+# Command line options
+feature('midl-stubless-proxy', ['yes', 'no'], ['propagated'] )
+feature('midl-robust', ['yes', 'no'], ['propagated'] )
+
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>yes'], ['/Oicf' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>no' ], ['/Oic' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>yes' ], ['/robust' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>no' ], ['/no_robust'])
+
+# Architecture-specific options
+architecture_x86 = ['<architecture>' , '<architecture>x86']
+address_model_32 = ['<address-model>', '<address-model>32']
+address_model_64 = ['<address-model>', '<address-model>64']
+
+flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/' + m for ar in architecture_x86 for m in address_model_32 ], ['/win32'])
+flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/<address-model>64' for ar in architecture_x86], ['/x64'])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<architecture>ia64/' + m for m in address_model_64], ['/ia64'])
+
+flags('midl.compile.idl', 'DEFINES', [], ['<define>'])
+flags('midl.compile.idl', 'UNDEFS', [], ['<undef>'])
+flags('midl.compile.idl', 'INCLUDES', [], ['<include>'])
+
+
+builtin.register_c_compiler('midl.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], [])
+
+
+# MIDL does not always generate '%_proxy.c' and '%_dlldata.c'. This behavior
+# depends on contents of the source IDL file. Calling TOUCH_FILE below ensures
+# that both files will be created so bjam will not try to recreate them
+# constantly.
+get_manager().engine().register_action(
+ 'midl.compile.idl',
+ '''midl /nologo @"@($(<[1]:W).rsp:E=
+"$(>:W)"
+-D$(DEFINES)
+"-I$(INCLUDES)"
+-U$(UNDEFS)
+$(MIDLFLAGS)
+/tlb "$(<[1]:W)"
+/h "$(<[2]:W)"
+/iid "$(<[3]:W)"
+/proxy "$(<[4]:W)"
+/dlldata "$(<[5]:W)")"
+{touch} "$(<[4]:W)"
+{touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
diff --git a/tools/build/v2/tools/msvc.jam b/tools/build/v2/tools/msvc.jam
index e33a66d22b..22548323ad 100644
--- a/tools/build/v2/tools/msvc.jam
+++ b/tools/build/v2/tools/msvc.jam
@@ -736,7 +736,11 @@ local rule configure-really ( version ? : options * )
# version from the path.
# FIXME: We currently detect both Microsoft Visual Studio 9.0 and
# 9.0express as 9.0 here.
- if [ MATCH "(Microsoft Visual Studio 10)" : $(command) ]
+ if [ MATCH "(Microsoft Visual Studio 11)" : $(command) ]
+ {
+ version = 11.0 ;
+ }
+ else if [ MATCH "(Microsoft Visual Studio 10)" : $(command) ]
{
version = 10.0 ;
}
@@ -1351,7 +1355,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
# Known toolset versions, in order of preference.
-.known-versions = 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;
+.known-versions = 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;
# Version aliases.
.version-alias-6 = 6.0 ;
@@ -1360,6 +1364,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
.version-alias-8 = 8.0 ;
.version-alias-9 = 9.0 ;
.version-alias-10 = 10.0 ;
+.version-alias-11 = 11.0 ;
# Names of registry keys containing the Visual C++ installation path (relative
# to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft").
@@ -1372,6 +1377,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
.version-9.0express-reg = "VCExpress\\9.0\\Setup\\VC" ;
.version-10.0-reg = "VisualStudio\\10.0\\Setup\\VC" ;
.version-10.0express-reg = "VCExpress\\10.0\\Setup\\VC" ;
+.version-11.0-reg = "VisualStudio\\11.0\\Setup\\VC" ;
# Visual C++ Toolkit 2003 does not store its installation path in the registry.
# The environment variable 'VCToolkitInstallDir' and the default installation
diff --git a/tools/build/v2/tools/msvc.py b/tools/build/v2/tools/msvc.py
new file mode 100644
index 0000000000..f4448daab4
--- /dev/null
+++ b/tools/build/v2/tools/msvc.py
@@ -0,0 +1,1198 @@
+# Copyright (c) 2003 David Abrahams.
+# Copyright (c) 2005 Vladimir Prus.
+# Copyright (c) 2005 Alexey Pakhunov.
+# Copyright (c) 2006 Bojan Resnik.
+# Copyright (c) 2006 Ilya Sokolov.
+# Copyright (c) 2007 Rene Rivera
+# Copyright (c) 2008 Jurko Gospodnetic
+# Copyright (c) 2011 Juraj Ivancic
+#
+# Use, modification and distribution is subject to the Boost Software
+# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
+# http://www.boost.org/LICENSE_1_0.txt)
+
+################################################################################
+#
+# MSVC Boost Build toolset module.
+# --------------------------------
+#
+# All toolset versions need to have their location either auto-detected or
+# explicitly specified except for the special 'default' version that expects the
+# environment to find the needed tools or report an error.
+#
+################################################################################
+
+from os import environ
+import os.path
+import re
+import _winreg
+
+import bjam
+
+from b2.tools import common, rc, pch, builtin, mc, midl
+from b2.build import feature, type, toolset, generators, property_set
+from b2.build.property import Property
+from b2.util import path
+from b2.manager import get_manager
+from b2.build.generators import Generator
+from b2.build.toolset import flags
+from b2.util.utility import to_seq, on_windows
+from b2.tools.common import Configurations
+
+__debug = None
+
+def debug():
+ global __debug
+ if __debug is None:
+ __debug = "--debug-configuration" in bjam.variable("ARGV")
+ return __debug
+
+
+# It is not yet clear what to do with Cygwin on python port.
+def on_cygwin():
+ return False
+
+
+type.register('MANIFEST', ['manifest'])
+feature.feature('embed-manifest',['on','off'], ['incidental', 'propagated']) ;
+
+type.register('PDB',['pdb'])
+
+################################################################################
+#
+# Public rules.
+#
+################################################################################
+
+# Initialize a specific toolset version configuration. As the result, path to
+# compiler and, possible, program names are set up, and will be used when that
+# version of compiler is requested. For example, you might have:
+#
+# using msvc : 6.5 : cl.exe ;
+# using msvc : 7.0 : Y:/foo/bar/cl.exe ;
+#
+# The version parameter may be ommited:
+#
+# using msvc : : Z:/foo/bar/cl.exe ;
+#
+# The following keywords have special meanings when specified as versions:
+# - all - all detected but not yet used versions will be marked as used
+# with their default options.
+# - default - this is an equivalent to an empty version.
+#
+# Depending on a supplied version, detected configurations and presence 'cl.exe'
+# in the path different results may be achieved. The following table describes
+# the possible scenarios:
+#
+# Nothing "x.y"
+# Passed Nothing "x.y" detected, detected,
+# version detected detected cl.exe in path cl.exe in path
+#
+# default Error Use "x.y" Create "default" Use "x.y"
+# all None Use all None Use all
+# x.y - Use "x.y" - Use "x.y"
+# a.b Error Error Create "a.b" Create "a.b"
+#
+# "x.y" - refers to a detected version;
+# "a.b" - refers to an undetected version.
+#
+# FIXME: Currently the command parameter and the <compiler> property parameter
+# seem to overlap in duties. Remove this duplication. This seems to be related
+# to why someone started preparing to replace init with configure rules.
+
+def init(version = None, command = None, options = None):
+ # When initialized from
+ # using msvc : x.0 ;
+ # we get version as a single element list i.e. ['x.0'],
+ # but when specified from the command line we get a string i.e. 'x.0'.
+ # We want to work with a string, so unpack the list if needed.
+ is_single_element_list = (isinstance(version,list) and len(version) == 1)
+ assert(version==None or isinstance(version,str) or is_single_element_list)
+ if is_single_element_list:
+ version = version[0]
+
+ options = to_seq(options)
+ command = to_seq(command)
+
+ if command:
+ options.append("<command>"+command)
+ configure(version,options)
+
+def configure(version=None, options=None):
+ if version == "all":
+ if options:
+ raise RuntimeError("MSVC toolset configuration: options should be empty when '{}' is specified.".format(version))
+
+ # Configure (i.e. mark as used) all registered versions.
+ all_versions = __versions.all()
+ if not all_versions:
+ if debug():
+ print "notice: [msvc-cfg] Asked to configure all registered" \
+ "msvc toolset versions when there are none currently" \
+ "registered." ;
+ else:
+ for v in all_versions:
+ # Note that there is no need to skip already configured
+ # versions here as this will request configure-really rule
+ # to configure the version using default options which will
+ # in turn cause it to simply do nothing in case the version
+ # has already been configured.
+ configure_really(v)
+ elif version == "default":
+ configure_really(None,options)
+ else:
+ configure_really(version, options)
+
+def extend_conditions(conditions,exts):
+ return [ cond + '/' + ext for cond in conditions for ext in exts ]
+
+def configure_version_specific(toolset_arg, version, conditions):
+ # Starting with versions 7.0, the msvc compiler have the /Zc:forScope and
+ # /Zc:wchar_t options that improve C++ standard conformance, but those
+ # options are off by default. If we are sure that the msvc version is at
+ # 7.*, add those options explicitly. We can be sure either if user specified
+ # version 7.* explicitly or if we auto-detected the version ourselves.
+ if not re.match('^6\\.', version):
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',conditions, ['/Zc:forScope','/Zc:wchar_t'])
+ toolset.flags('{}.compile.c++'.format(toolset_arg), 'C++FLAGS',conditions, ['/wd4675'])
+
+ # Explicitly disable the 'function is deprecated' warning. Some msvc
+ # versions have a bug, causing them to emit the deprecation warning even
+ # with /W0.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>off']), ['/wd4996'])
+ if re.match('^[78]\\.', version):
+ # 64-bit compatibility warning deprecated since 9.0, see
+ # http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>all']), ['/Wp64'])
+
+ #
+ # Processor-specific optimization.
+ #
+ if re.match('^[67]', version ):
+ # 8.0 deprecates some of the options.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed','<optimization>space']), ['/Ogiy', '/Gs'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed']), ['/Ot'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>space']), ['/Os'])
+
+ cpu_arch_i386_cond = extend_conditions(conditions, __cpu_arch_i386)
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>']),['/GB'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>i386']),['/G3'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>i486']),['/G4'])
+
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g5]), ['/G5'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g6]), ['/G6'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g7]), ['/G7'])
+
+ # Improve floating-point accuracy. Otherwise, some of C++ Boost's "math"
+ # tests will fail.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', conditions, ['/Op'])
+
+ # 7.1 and below have single-threaded static RTL.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/ML'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MLd'])
+ else:
+ # 8.0 and above adds some more options.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' for a in __cpu_arch_amd64]), ['/favor:blend'])
+
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_em64t]), ['/favor:EM64T'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_amd64]), ['/favor:AMD64'])
+
+ # 8.0 and above only has multi-threaded static RTL.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/MT'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MTd'])
+
+ # Specify target machine type so the linker will not need to guess.
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_amd64), ['/MACHINE:X64'])
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_i386), ['/MACHINE:X86'])
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_ia64), ['/MACHINE:IA64'])
+
+ # Make sure that manifest will be generated even if there is no
+ # dependencies to put there.
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions,["<embed-manifest>off"]), ['/MANIFEST'])
+
+
+# Registers this toolset including all of its flags, features & generators. Does
+# nothing on repeated calls.
+
+def register_toolset():
+ if not 'msvc' in feature.values('toolset'):
+ register_toolset_really()
+
+
+engine = get_manager().engine()
+
+# this rule sets up the pdb file that will be used when generating static
+# libraries and the debug-store option is database, so that the compiler
+# puts all debug info into a single .pdb file named after the library
+#
+# Poking at source targets this way is probably not clean, but it's the
+# easiest approach.
+def archive(targets, sources=None, properties=None):
+ bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
+
+# Declare action for creating static libraries. If library exists, remove it
+# before adding files. See
+# http://article.gmane.org/gmane.comp.lib.boost.build/4241 for rationale.
+if not on_cygwin():
+ engine.register_action(
+ 'msvc.archive',
+ '''if exist "$(<[1])" DEL "$(<[1])"
+ $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=archive)
+else:
+ engine.register_action(
+ 'msvc.archive',
+ '''{rm} "$(<[1])"
+ $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"'''.format(rm=common.rm_command()),
+ function=archive)
+
+# For the assembler the following options are turned on by default:
+#
+# -Zp4 align structures to 4 bytes
+# -Cp preserve case of user identifiers
+# -Cx preserve case in publics, externs
+#
+engine.register_action(
+ 'msvc.compile.asm',
+ '$(.ASM) -c -Zp4 -Cp -Cx -D$(DEFINES) $(ASMFLAGS) $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"' )
+
+
+# Equivalent to [ on $(target) return $(prefix)$(var)$(suffix) ]. Note that $(var) can be a list.
+def expand_target_variable(target,var,prefix=None,suffix=None):
+ list = bjam.call( 'get-target-variable', target, var )
+ return " ".join([ ("" if prefix is None else prefix) + elem + ("" if suffix is None else suffix) for elem in list ])
+
+
+compile_c_cpp_pch = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include $(.escaped-double-quote)$(>[1]:D=)$(.escaped-double-quote)$(.nl))" $(.CC.FILTER)'''
+# Action for running the C/C++ compiler using precompiled headers. An already
+# built source file for compiling the precompiled headers is expected to be
+# given as one of the source parameters.
+compile_c_cpp_pch_s = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'''
+
+def get_rspline(targets, lang_opt):
+ result = lang_opt + ' ' + \
+ expand_target_variable(targets, 'UNDEFS', '-U' ) + ' ' + \
+ expand_target_variable(targets, 'CFLAGS' ) + ' ' + \
+ expand_target_variable(targets, 'C++FLAGS' ) + ' ' + \
+ expand_target_variable(targets, 'OPTIONS' ) + ' -c ' + \
+ expand_target_variable(targets, 'DEFINES', '\n-D' ) + ' ' + \
+ expand_target_variable(targets, 'INCLUDES', '\n"-I', '"' )
+ bjam.call('set-target-variable', targets, 'CC_RSPLINE', result)
+
+def compile_c(targets, sources = [], properties = None):
+ get_manager().engine().set_target_variable( targets[1], 'C++FLAGS', '' )
+ get_rspline(targets, '-TC')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ compile_c_cpp(targets,sources)
+
+def compile_c_preprocess(targets, sources = [], properties = None):
+ get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
+ get_rspline(targets, '-TC')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ preprocess_c_cpp(targets,sources)
+
+def compile_c_pch(targets, sources = [], properties = []):
+ get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
+ get_rspline([targets[1]], '-TC')
+ get_rspline([targets[2]], '-TC')
+ pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
+ sources += pch_source
+ if pch_source:
+ get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
+ get_manager().engine().add_dependency(targets,pch_source)
+ compile_c_cpp_pch_s(targets,sources)
+ else:
+ get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
+ compile_c_cpp_pch(targets,sources)
+
+toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] )
+
+def compile_cpp(targets,sources=[],properties=None):
+ get_rspline(targets,'-TP')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ compile_c_cpp(targets,sources)
+
+def compile_cpp_preprocess(targets,sources=[],properties=None):
+ get_rspline(targets,'-TP')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ preprocess_c_cpp(targets,sources)
+
+def compile_cpp_pch(targets,sources=[],properties=None):
+ get_rspline([targets[1]], '-TP')
+ get_rspline([targets[2]], '-TP')
+ pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
+ sources += pch_source
+ if pch_source:
+ get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
+ get_manager().engine().add_dependency(targets,pch_source)
+ compile_c_cpp_pch_s(targets,sources)
+ else:
+ get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
+ compile_c_cpp_pch(targets,sources)
+
+
+# Action for running the C/C++ compiler without using precompiled headers.
+#
+# WARNING: Synchronize any changes this in action with intel-win
+#
+# Notes regarding PDB generation, for when we use <debug-symbols>on/<debug-store>database
+#
+# 1. PDB_CFLAG is only set for <debug-symbols>on/<debug-store>database, ensuring that the /Fd flag is dropped if PDB_CFLAG is empty
+#
+# 2. When compiling executables's source files, PDB_NAME is set on a per-source file basis by rule compile-c-c++.
+# The linker will pull these into the executable's PDB
+#
+# 3. When compiling library's source files, PDB_NAME is updated to <libname>.pdb for each source file by rule archive,
+# as in this case the compiler must be used to create a single PDB for our library.
+#
+
+compile_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'
+engine.register_action(
+ 'msvc.compile.c',
+ compile_action,
+ function=compile_c,
+ bound_list=['PDB_NAME'])
+
+engine.register_action(
+ 'msvc.compile.c++',
+ compile_action,
+ function=compile_cpp,
+ bound_list=['PDB_NAME'])
+
+
+preprocess_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"'
+
+engine.register_action(
+ 'msvc.preprocess.c',
+ preprocess_action,
+ function=compile_c_preprocess,
+ bound_list=['PDB_NAME'])
+
+engine.register_action(
+ 'msvc.preprocess.c++',
+ preprocess_action,
+ function=compile_cpp_preprocess,
+ bound_list=['PDB_NAME'])
+
+def compile_c_cpp(targets,sources=None):
+ pch_header = bjam.call('get-target-variable',targets[0],'PCH_HEADER')
+ pch_file = bjam.call('get-target-variable',targets[0],'PCH_FILE')
+ if pch_header: get_manager().engine().add_dependency(targets[0],pch_header)
+ if pch_file: get_manager().engine().add_dependency(targets[0],pch_file)
+ bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
+
+def preprocess_c_cpp(targets,sources=None):
+ #same as above
+ return compile_c_cpp(targets,sources)
+
+# Action for running the C/C++ compiler using precompiled headers. In addition
+# to whatever else it needs to compile, this action also adds a temporary source
+# .cpp file used to compile the precompiled headers themselves.
+
+engine.register_action(
+ 'msvc.compile.c.pch',
+ None, # action set by the function
+ function=compile_c_pch)
+
+engine.register_action(
+ 'msvc.compile.c++.pch',
+ None, # action set by the function
+ function=compile_cpp_pch)
+
+
+# See midl.py for details.
+#
+engine.register_action(
+ 'msvc.compile.idl',
+ '''$(.IDL) /nologo @"@($(<[1]:W).rsp:E=
+"$(>:W)"
+-D$(DEFINES)
+"-I$(INCLUDES:W)"
+-U$(UNDEFS)
+$(MIDLFLAGS)
+/tlb "$(<[1]:W)"
+/h "$(<[2]:W)"
+/iid "$(<[3]:W)"
+/proxy "$(<[4]:W)"
+/dlldata "$(<[5]:W)")"
+ {touch} "$(<[4]:W)"
+ {touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
+
+engine.register_action(
+ 'msvc.compile.mc',
+ '$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"')
+
+engine.register_action(
+ 'msvc.compile.rc',
+ '$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"')
+
+def link_dll(targets,sources=None,properties=None):
+ get_manager().engine().add_dependency(targets,bjam.call('get-target-variable',targets,'DEF_FILE'))
+ manifest(targets, sources, properties)
+
+def manifest(targets,sources=None,properties=None):
+ if 'on' in properties.get('<embed-manifest>'):
+ get_manager().engine().set_update_action('msvc.manifest', targets, sources, properties)
+
+
+# Incremental linking a DLL causes no end of problems: if the actual exports do
+# not change, the import .lib file is never updated. Therefore, the .lib is
+# always out-of-date and gets rebuilt every time. I am not sure that incremental
+# linking is such a great idea in general, but in this case I am sure we do not
+# want it.
+
+# Windows manifest is a new way to specify dependencies on managed DotNet
+# assemblies and Windows native DLLs. The manifests are embedded as resources
+# and are useful in any PE target (both DLL and EXE).
+
+if not on_cygwin():
+ engine.register_action(
+ 'msvc.link',
+ '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
+if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
+ function=manifest,
+ bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest',
+ '''if exist "$(<[1]).manifest" (
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
+ )''')
+
+ engine.register_action(
+ 'msvc.link.dll',
+ '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
+if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
+ function=link_dll,
+ bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest.dll',
+ '''if exist "$(<[1]).manifest" (
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
+ )''')
+else:
+ engine.register_action(
+ 'msvc.link',
+ '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=manifest,
+ bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest',
+ '''if test -e "$(<[1]).manifest"; then
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
+ fi''')
+
+ engine.register_action(
+ 'msvc.link.dll',
+ '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=link_dll,
+ bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest.dll',
+ '''if test -e "$(<[1]).manifest"; then
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
+ fi''')
+
+
+################################################################################
+#
+# Classes.
+#
+################################################################################
+
+class MsvcPchGenerator(pch.PchGenerator):
+
+ # Inherit the __init__ method
+
+ def run_pch(self, project, name, prop_set, sources):
+ # Find the header in sources. Ignore any CPP sources.
+ pch_header = None
+ pch_source = None
+ for s in sources:
+ if type.is_derived(s.type(), 'H'):
+ pch_header = s
+ elif type.is_derived(s.type(), 'CPP') or type.is_derived(s.type(), 'C'):
+ pch_source = s
+
+ if not pch-header:
+ raise RuntimeError( "can not build pch without pch-header" )
+
+ # If we do not have the PCH source - that is fine. We will just create a
+ # temporary .cpp file in the action.
+ temp_prop_set = property_set.create([Property('pch-source',pch_source)]+prop_set.all())
+ generated = Generator.run(project,name,temp_prop_set,pch_header)
+ pch_file = None
+ for g in generated:
+ if type.is_derived(g.type(), 'PCH'):
+ pch_file = g
+ return property_set.create([Property('pch-header',pch_header),Property('pch-file',pch_file)]+generated)
+
+
+################################################################################
+#
+# Local rules.
+#
+################################################################################
+
+# Detects versions listed as '_known_versions' by checking registry information,
+# environment variables & default paths. Supports both native Windows and
+# Cygwin.
+def auto_detect_toolset_versions():
+ if on_windows() or on_cygwin():
+ for version in _known_versions:
+ versionVarName = '__version_{}_reg'.format(version.replace('.','_'))
+ if versionVarName in globals():
+ vc_path = None
+ for x in [ '', 'Wow6432Node\\' ]:
+ try:
+ with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\{}{}'.format(x, globals()[versionVarName])) as reg_key:
+ vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0]
+ except:
+ pass
+ if vc_path:
+ vc_path = os.path.join(vc_path,'bin')
+ register_configuration(version,os.path.normpath(vc_path))
+
+ for i in _known_versions:
+ if not i in __versions.all():
+ register_configuration(i,default_path(i))
+
+
+# Worker rule for toolset version configuration. Takes an explicit version id or
+# nothing in case it should configure the default toolset version (the first
+# registered one or a new 'default' one in case no toolset versions have been
+# registered yet).
+#
+
+def configure_really(version=None, options=[]):
+ v = version
+ if not v:
+ # Take the first registered (i.e. auto-detected) version.
+ version = __versions.first()
+ v = version
+
+ # Note: 'version' can still be empty at this point if no versions have
+ # been auto-detected.
+ if not version:
+ version = "default"
+
+ # Version alias -> real version number.
+ version = globals().get("__version_alias_{}".format(version), version)
+
+ # Check whether the selected configuration is already in use.
+ if version in __versions.used():
+ # Allow multiple 'toolset.using' calls for the same configuration if the
+ # identical sets of options are used.
+ if options and options != __versions.get(version,'options'):
+ raise RuntimeError("MSVC toolset configuration: Toolset version '$(version)' already configured.".format(version))
+ else:
+ # Register a new configuration.
+ __versions.register(version)
+
+ # Add user-supplied to auto-detected options.
+ version_opts = __versions.get(version, 'options')
+ if (version_opts):
+ options = version_opts + options
+
+ # Mark the configuration as 'used'.
+ __versions.use(version)
+ # Generate conditions and save them.
+ conditions = common.check_init_parameters('msvc', None, ('version', v))
+ __versions.set(version, 'conditions', conditions)
+ command = feature.get_values('<command>', options)
+
+ # If version is specified, we try to search first in default paths, and
+ # only then in PATH.
+ command = common.get_invocation_command('msvc', 'cl.exe', command, default_paths(version))
+ common.handle_options('msvc', conditions, command, options)
+
+ if not version:
+ # Even if version is not explicitly specified, try to detect the
+ # version from the path.
+ # FIXME: We currently detect both Microsoft Visual Studio 9.0 and
+ # 9.0express as 9.0 here.
+ if re.search("Microsoft Visual Studio 11", command):
+ version = '11.0'
+ if re.search("Microsoft Visual Studio 10", command):
+ version = '10.0'
+ elif re.search("Microsoft Visual Studio 9", command):
+ version = '9.0'
+ elif re.search("Microsoft Visual Studio 8", command):
+ version = '8.0'
+ elif re.search("NET 2003[\/\\]VC7", command):
+ version = '7.1'
+ elif re.search("Microsoft Visual C\\+\\+ Toolkit 2003", command):
+ version = '7.1toolkit'
+ elif re.search(".NET[\/\\]VC7", command):
+ version = '7.0'
+ else:
+ version = '6.0'
+
+ # Generate and register setup command.
+
+ below_8_0 = re.search("^[67]\\.",version) != None
+
+ if below_8_0:
+ cpu = ['i386']
+ else:
+ cpu = ['i386', 'amd64', 'ia64']
+
+ setup_scripts = {}
+
+ if command:
+ # TODO: Note that if we specify a non-existant toolset version then
+ # this rule may find and use a corresponding compiler executable
+ # belonging to an incorrect toolset version. For example, if you
+ # have only MSVC 7.1 installed, have its executable on the path and
+ # specify you want Boost Build to use MSVC 9.0, then you want Boost
+ # Build to report an error but this may cause it to silently use the
+ # MSVC 7.1 compiler even though it thinks it is using the msvc-9.0
+ # toolset version.
+ command = common.get_absolute_tool_path(command)
+
+ if command:
+ parent = os.path.dirname(os.path.normpath(command))
+ # Setup will be used if the command name has been specified. If
+ # setup is not specified explicitly then a default setup script will
+ # be used instead. Setup scripts may be global or arhitecture/
+ # /platform/cpu specific. Setup options are used only in case of
+ # global setup scripts.
+
+ # Default setup scripts provided with different VC distributions:
+ #
+ # VC 7.1 had only the vcvars32.bat script specific to 32 bit i386
+ # builds. It was located in the bin folder for the regular version
+ # and in the root folder for the free VC 7.1 tools.
+ #
+ # Later 8.0 & 9.0 versions introduce separate platform specific
+ # vcvars*.bat scripts (e.g. 32 bit, 64 bit AMD or 64 bit Itanium)
+ # located in or under the bin folder. Most also include a global
+ # vcvarsall.bat helper script located in the root folder which runs
+ # one of the aforementioned vcvars*.bat scripts based on the options
+ # passed to it. So far only the version coming with some PlatformSDK
+ # distributions does not include this top level script but to
+ # support those we need to fall back to using the worker scripts
+ # directly in case the top level script can not be found.
+
+ global_setup = feature.get_values('<setup>',options)
+ if global_setup:
+ global_setup = global_setup[0]
+ else:
+ global_setup = None
+
+ if not below_8_0 and not global_setup:
+ global_setup = locate_default_setup(command,parent,'vcvarsall.bat')
+
+
+ default_setup = {
+ 'amd64' : 'vcvarsx86_amd64.bat',
+ 'i386' : 'vcvars32.bat',
+ 'ia64' : 'vcvarsx86_ia64.bat' }
+
+ # http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and
+ # http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx
+ # mention an x86_IPF option, that seems to be a documentation bug
+ # and x86_ia64 is the correct option.
+ default_global_setup_options = {
+ 'amd64' : 'x86_amd64',
+ 'i386' : 'x86',
+ 'ia64' : 'x86_ia64' }
+
+ somehow_detect_the_itanium_platform = None
+ # When using 64-bit Windows, and targeting 64-bit, it is possible to
+ # use a native 64-bit compiler, selected by the "amd64" & "ia64"
+ # parameters to vcvarsall.bat. There are two variables we can use --
+ # PROCESSOR_ARCHITECTURE and PROCESSOR_IDENTIFIER. The first is
+ # 'x86' when running 32-bit Windows, no matter which processor is
+ # used, and 'AMD64' on 64-bit windows on x86 (either AMD64 or EM64T)
+ # Windows.
+ #
+ if re.search( 'AMD64', environ[ "PROCESSOR_ARCHITECTURE" ] ) != None:
+ default_global_setup_options[ 'amd64' ] = 'amd64'
+ # TODO: The same 'native compiler usage' should be implemented for
+ # the Itanium platform by using the "ia64" parameter. For this
+ # though we need someone with access to this platform who can find
+ # out how to correctly detect this case.
+ elif somehow_detect_the_itanium_platform:
+ default_global_setup_options[ 'ia64' ] = 'ia64'
+
+ setup_prefix = "call "
+ setup_suffix = """ >nul\n"""
+ if on_cygwin():
+ setup_prefix = "cmd.exe /S /C call "
+ setup_suffix = " \">nul\" \"&&\" "
+
+ for c in cpu:
+ setup_options = None
+ setup_cpu = feature.get_values('<setup-{}>'.format(c),options)
+
+ if not setup_cpu:
+ if global_setup:
+ setup_cpu = global_setup
+ # If needed we can easily add using configuration flags
+ # here for overriding which options get passed to the
+ # global setup command for which target platform:
+ # setup_options = feature.get_values('<setup-options-{}>'.format(c),options)
+ if not setup_options:
+ setup_options = default_global_setup_options[ c ]
+ else:
+ setup_cpu = locate_default_setup(command, parent, default_setup[ c ])
+
+ # Cygwin to Windows path translation.
+ # setup-$(c) = "\""$(setup-$(c):W)"\"" ;
+
+ # Append setup options to the setup name and add the final setup
+ # prefix & suffix.
+ setup_scripts[ c ] = '{}"{}" {}{}'.format(setup_prefix, setup_cpu, setup_options, setup_suffix)
+
+ # Get tool names (if any) and finish setup.
+ compiler = feature.get_values("<compiler>", options)
+ if not compiler:
+ compiler = "cl"
+
+ linker = feature.get_values("<linker>", options)
+ if not linker:
+ linker = "link"
+
+ resource_compiler = feature.get_values("<resource-compiler>", options)
+ if not resource_compiler:
+ resource_compiler = "rc"
+
+ # Turn on some options for i386 assembler
+ # -coff generate COFF format object file (compatible with cl.exe output)
+ default_assembler_amd64 = 'ml64'
+ default_assembler_i386 = 'ml -coff'
+ default_assembler_ia64 = 'ias'
+
+ assembler = feature.get_values('<assembler>',options)
+
+ idl_compiler = feature.get_values('<idl-compiler>',options)
+ if not idl_compiler:
+ idl_compiler = 'midl'
+
+ mc_compiler = feature.get_values('<mc-compiler>',options)
+ if not mc_compiler:
+ mc_compiler = 'mc'
+
+ manifest_tool = feature.get_values('<manifest-tool>',options)
+ if not manifest_tool:
+ manifest_tool = 'mt'
+
+ cc_filter = feature.get_values('<compiler-filter>',options)
+
+ for c in cpu:
+ cpu_conditions = [ condition + '/' + arch for arch in globals()['__cpu_arch_{}'.format(c)] for condition in conditions ]
+
+ setup_script = setup_scripts.get(c, '')
+
+ if debug():
+ for cpu_condition in cpu_conditions:
+ print "notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script)
+
+ cpu_assembler = assembler
+ if not cpu_assembler:
+ cpu_assembler = locals()['default_assembler_{}'.format(c)]
+
+ toolset.flags('msvc.compile', '.CC' , cpu_conditions, ['{}{} /Zm800 -nologo' .format(setup_script, compiler)])
+ toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{} -nologo' .format(setup_script, resource_compiler)])
+ toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} ' .format(setup_script, cpu_assembler)])
+ toolset.flags('msvc.link' , '.LD' , cpu_conditions, ['{}{} /NOLOGO /INCREMENTAL:NO'.format(setup_script, linker)])
+ toolset.flags('msvc.archive', '.LD' , cpu_conditions, ['{}{} /lib /NOLOGO' .format(setup_script, linker)])
+ toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{} ' .format(setup_script, idl_compiler)])
+ toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{} ' .format(setup_script, mc_compiler)])
+ toolset.flags('msvc.link' , '.MT' , cpu_conditions, ['{}{} -nologo' .format(setup_script, manifest_tool)])
+
+ if cc_filter:
+ toolset.flags('msvc', '.CC.FILTER', cpu_conditions, ['"|" {}'.format(cc_filter)])
+
+ # Set version-specific flags.
+ configure_version_specific('msvc', version, conditions)
+
+
+# Returns the default installation path for the given version.
+#
+def default_path(version):
+ # Use auto-detected path if possible.
+ options = __versions.get(version, 'options')
+ tmp_path = None
+ if options:
+ tmp_path = feature.get_values('<command>', options)
+
+ if tmp_path:
+ tmp_path="".join(tmp_path)
+ tmp_path=os.path.dirname(tmp_path)
+ else:
+ env_var_var_name = '__version_{}_env'.format(version.replace('.','_'))
+ vc_path = None
+ if env_var_var_name in globals():
+ env_var_name = globals()[env_var_var_name]
+ if env_var_name in os.environ:
+ vc_path = environ[env_var_name]
+ if vc_path:
+ vc_path = os.path.join(vc_path,globals()['__version_{}_envpath'.format(version.replace('.','_'))])
+ tmp_path = os.path.normpath(vc_path)
+
+ var_name = '__version_{}_path'.format(version.replace('.','_'))
+ if not tmp_path and var_name in globals():
+ tmp_path = os.path.normpath(os.path.join(common.get_program_files_dir(), globals()[var_name]))
+ return tmp_path
+
+
+# Returns either the default installation path (if 'version' is not empty) or
+# list of all known default paths (if no version is given)
+#
+def default_paths(version = None):
+ possible_paths = []
+ if version:
+ path = default_path(version)
+ if path:
+ possible_paths.append(path)
+ else:
+ for i in _known_versions:
+ path = default_path(i)
+ if path:
+ possible_paths.append(path)
+ return possible_paths
+
+
+class MsvcLinkingGenerator(builtin.LinkingGenerator):
+ # Calls the base version. If necessary, also create a target for the
+ # manifest file.specifying source's name as the name of the created
+ # target. As result, the PCH will be named whatever.hpp.gch, and not
+ # whatever.gch.
+ def generated_targets(self, sources, prop_set, project, name):
+ result = builtin.LinkingGenerator.generated_targets(self, sources, prop_set, project, name)
+ if result:
+ name_main = result[0].name()
+ action = result[0].action()
+
+ if prop_set.get('<debug-symbols>') == 'on':
+ # We force exact name on PDB. The reason is tagging -- the tag rule may
+ # reasonably special case some target types, like SHARED_LIB. The tag rule
+ # will not catch PDB, and it cannot even easily figure if PDB is paired with
+ # SHARED_LIB or EXE or something else. Because PDB always get the
+ # same name as the main target, with .pdb as extension, just force it.
+ target = FileTarget(name_main.split_ext()[0]+'.pdb','PDB',project,action,True)
+ registered_target = virtual_target.register(target)
+ if target != registered_target:
+ action.replace_targets(target,registered_target)
+ result.append(registered_target)
+ if prop_set.get('<embed-manifest>') == 'off':
+ # Manifest is evil target. It has .manifest appened to the name of
+ # main target, including extension. E.g. a.exe.manifest. We use 'exact'
+ # name because to achieve this effect.
+ target = FileTarget(name_main+'.manifest', 'MANIFEST', project, action, True)
+ registered_target = virtual_target.register(target)
+ if target != registered_target:
+ action.replace_targets(target,registered_target)
+ result.append(registered_target)
+ return result
+
+
+# Unsafe worker rule for the register-toolset() rule. Must not be called
+# multiple times.
+
+def register_toolset_really():
+ feature.extend('toolset', ['msvc'])
+
+ # Intel and msvc supposedly have link-compatible objects.
+ feature.subfeature( 'toolset', 'msvc', 'vendor', 'intel', ['propagated', 'optional'])
+
+ # Inherit MIDL flags.
+ toolset.inherit_flags('msvc', 'midl')
+
+ # Inherit MC flags.
+ toolset.inherit_flags('msvc','mc')
+
+ # Dynamic runtime comes only in MT flavour.
+ toolset.add_requirements(['<toolset>msvc,<runtime-link>shared:<threading>multi'])
+
+ # Declare msvc toolset specific features.
+ feature.feature('debug-store', ['object', 'database'], ['propagated'])
+ feature.feature('pch-source', [], ['dependency', 'free'])
+
+ # Declare generators.
+
+ # TODO: Is it possible to combine these? Make the generators
+ # non-composing so that they do not convert each source into a separate
+ # .rsp file.
+ generators.register(MsvcLinkingGenerator('msvc.link', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['EXE'], ['<toolset>msvc']))
+ generators.register(MsvcLinkingGenerator('msvc.link.dll', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['SHARED_LIB','IMPORT_LIB'], ['<toolset>msvc']))
+
+ builtin.register_archiver('msvc.archive', ['OBJ'], ['STATIC_LIB'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c++', ['CPP'], ['OBJ'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c', ['C'], ['OBJ'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c++.preprocess', ['CPP'], ['PREPROCESSED_CPP'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c.preprocess', ['C'], ['PREPROCESSED_C'], ['<toolset>msvc'])
+
+ # Using 'register-c-compiler' adds the build directory to INCLUDES.
+ builtin.register_c_compiler('msvc.compile.rc', ['RC'], ['OBJ(%_res)'], ['<toolset>msvc'])
+ generators.override('msvc.compile.rc', 'rc.compile.resource')
+ generators.register_standard('msvc.compile.asm', ['ASM'], ['OBJ'], ['<toolset>msvc'])
+
+ builtin.register_c_compiler('msvc.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], ['<toolset>msvc'])
+ generators.override('msvc.compile.idl', 'midl.compile.idl')
+
+ generators.register_standard('msvc.compile.mc', ['MC'], ['H','RC'], ['<toolset>msvc'])
+ generators.override('msvc.compile.mc', 'mc.compile')
+
+ # Note: the 'H' source type will catch both '.h' and '.hpp' headers as
+ # the latter have their HPP type derived from H. The type of compilation
+ # is determined entirely by the destination type.
+ generators.register(MsvcPchGenerator('msvc.compile.c.pch', False, ['H'], ['C_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
+ generators.register(MsvcPchGenerator('msvc.compile.c++.pch', False, ['H'], ['CPP_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
+
+ generators.override('msvc.compile.c.pch', 'pch.default-c-pch-generator')
+ generators.override('msvc.compile.c++.pch', 'pch.default-cpp-pch-generator')
+
+ toolset.flags('msvc.compile', 'PCH_FILE' , ['<pch>on'], ['<pch-file>' ])
+ toolset.flags('msvc.compile', 'PCH_SOURCE', ['<pch>on'], ['<pch-source>'])
+ toolset.flags('msvc.compile', 'PCH_HEADER', ['<pch>on'], ['<pch-header>'])
+
+ #
+ # Declare flags for compilation.
+ #
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>speed'], ['/O2'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>space'], ['/O1'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium ], ['/G1'])
+ toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium2 ], ['/G2'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>object'], ['/Z7'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>database'], ['/Zi'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>off'], ['/Od'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>off'], ['/Ob0'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>on'], ['/Ob1'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>full'], ['/Ob2'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>on'], ['/W3'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>off'], ['/W0'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>all'], ['/W4'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings-as-errors>on'], ['/WX'])
+
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>off'], ['/EHs'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>on'], ['/EHsc'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>off'], ['/EHa'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>on'], ['/EHac'])
+
+ # By default 8.0 enables rtti support while prior versions disabled it. We
+ # simply enable or disable it explicitly so we do not have to depend on this
+ # default behaviour.
+ toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>on'], ['/GR'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>off'], ['/GR-'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>shared'], ['/MD'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>shared'], ['/MDd'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>static/<threading>multi'], ['/MT'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>static/<threading>multi'], ['/MTd'])
+
+ toolset.flags('msvc.compile', 'OPTIONS', [], ['<cflags>'])
+ toolset.flags('msvc.compile.c++', 'OPTIONS', [], ['<cxxflags>'])
+
+ toolset.flags('msvc.compile', 'PDB_CFLAG', ['<debug-symbols>on/<debug-store>database'],['/Fd'])
+
+ toolset.flags('msvc.compile', 'DEFINES', [], ['<define>'])
+ toolset.flags('msvc.compile', 'UNDEFS', [], ['<undef>'])
+ toolset.flags('msvc.compile', 'INCLUDES', [], ['<include>'])
+
+ # Declare flags for the assembler.
+ toolset.flags('msvc.compile.asm', 'USER_ASMFLAGS', [], ['<asmflags>'])
+
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<debug-symbols>on'], ['/Zi', '/Zd'])
+
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>on'], ['/W3'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>off'], ['/W0'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>all'], ['/W4'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings-as-errors>on'], ['/WX'])
+
+ toolset.flags('msvc.compile.asm', 'DEFINES', [], ['<define>'])
+
+ # Declare flags for linking.
+ toolset.flags('msvc.link', 'PDB_LINKFLAG', ['<debug-symbols>on/<debug-store>database'], ['/PDB']) # not used yet
+ toolset.flags('msvc.link', 'LINKFLAGS', ['<debug-symbols>on'], ['/DEBUG'])
+ toolset.flags('msvc.link', 'DEF_FILE', [], ['<def-file>'])
+
+ # The linker disables the default optimizations when using /DEBUG so we
+ # have to enable them manually for release builds with debug symbols.
+ toolset.flags('msvc', 'LINKFLAGS', ['<debug-symbols>on/<runtime-debugging>off'], ['/OPT:REF,ICF'])
+
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>console'], ['/subsystem:console'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>gui'], ['/subsystem:windows'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>wince'], ['/subsystem:windowsce'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>native'], ['/subsystem:native'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>auto'], ['/subsystem:posix'])
+
+ toolset.flags('msvc.link', 'OPTIONS', [], ['<linkflags>'])
+ toolset.flags('msvc.link', 'LINKPATH', [], ['<library-path>'])
+
+ toolset.flags('msvc.link', 'FINDLIBS_ST', ['<find-static-library>'])
+ toolset.flags('msvc.link', 'FINDLIBS_SA', ['<find-shared-library>'])
+ toolset.flags('msvc.link', 'LIBRARY_OPTION', ['<toolset>msvc'])
+ toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', ['<library-file>'])
+
+ toolset.flags('msvc.archive', 'AROPTIONS', [], ['<archiveflags>'])
+
+
+# Locates the requested setup script under the given folder and returns its full
+# path or nothing in case the script can not be found. In case multiple scripts
+# are found only the first one is returned.
+#
+# TODO: There used to exist a code comment for the msvc.init rule stating that
+# we do not correctly detect the location of the vcvars32.bat setup script for
+# the free VC7.1 tools in case user explicitly provides a path. This should be
+# tested or simply remove this whole comment in case this toolset version is no
+# longer important.
+#
+def locate_default_setup(command, parent, setup_name):
+ for setup in [os.path.join(dir,setup_name) for dir in [command,parent]]:
+ if os.path.exists(setup):
+ return setup
+ return None
+
+
+# Validates given path, registers found configuration and prints debug
+# information about it.
+#
+def register_configuration(version, path=None):
+ if path:
+ command = os.path.join(path, 'cl.exe')
+ if os.path.exists(command):
+ if debug():
+ print "notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command)
+ __versions.register(version)
+ __versions.set(version,'options',['<command>{}'.format(command)])
+
+
+################################################################################
+#
+# Startup code executed when loading this module.
+#
+################################################################################
+
+# Similar to Configurations, but remembers the first registered configuration.
+class MSVCConfigurations(Configurations):
+ def __init__(self):
+ Configurations.__init__(self)
+ self.first_ = None
+
+ def register(self, id):
+ Configurations.register(self,id)
+ if not self.first_:
+ self.first_ = id
+
+ def first(self):
+ return self.first_
+
+
+# List of all registered configurations.
+__versions = MSVCConfigurations()
+
+# Supported CPU architectures.
+__cpu_arch_i386 = [
+ '<architecture>/<address-model>',
+ '<architecture>/<address-model>32',
+ '<architecture>x86/<address-model>',
+ '<architecture>x86/<address-model>32']
+
+__cpu_arch_amd64 = [
+ '<architecture>/<address-model>64',
+ '<architecture>x86/<address-model>64']
+
+__cpu_arch_ia64 = [
+ '<architecture>ia64/<address-model>',
+ '<architecture>ia64/<address-model>64']
+
+
+# Supported CPU types (only Itanium optimization options are supported from
+# VC++ 2005 on). See
+# http://msdn2.microsoft.com/en-us/library/h66s5s0e(vs.90).aspx for more
+# detailed information.
+__cpu_type_g5 = ['i586', 'pentium', 'pentium-mmx' ]
+__cpu_type_g6 = ['i686', 'pentiumpro', 'pentium2', 'pentium3', 'pentium3m', 'pentium-m', 'k6',
+ 'k6-2', 'k6-3', 'winchip-c6', 'winchip2', 'c3', 'c3-2' ]
+__cpu_type_em64t = ['prescott', 'nocona', 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'mermon',
+ 'mermon-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale',
+ 'yorksfield', 'nehalem' ]
+__cpu_type_amd64 = ['k8', 'opteron', 'athlon64', 'athlon-fx']
+__cpu_type_g7 = ['pentium4', 'pentium4m', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp'
+ 'athlon-mp'] + __cpu_type_em64t + __cpu_type_amd64
+__cpu_type_itanium = ['itanium', 'itanium1', 'merced']
+__cpu_type_itanium2 = ['itanium2', 'mckinley']
+
+
+# Known toolset versions, in order of preference.
+_known_versions = ['11.0', '10.0', '10.0express', '9.0', '9.0express', '8.0', '8.0express', '7.1', '7.1toolkit', '7.0', '6.0']
+
+# Version aliases.
+__version_alias_6 = '6.0'
+__version_alias_6_5 = '6.0'
+__version_alias_7 = '7.0'
+__version_alias_8 = '8.0'
+__version_alias_9 = '9.0'
+__version_alias_10 = '10.0'
+__version_alias_11 = '11.0'
+
+# Names of registry keys containing the Visual C++ installation path (relative
+# to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft").
+__version_6_0_reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++"
+__version_7_0_reg = "VisualStudio\\7.0\\Setup\\VC"
+__version_7_1_reg = "VisualStudio\\7.1\\Setup\\VC"
+__version_8_0_reg = "VisualStudio\\8.0\\Setup\\VC"
+__version_8_0express_reg = "VCExpress\\8.0\\Setup\\VC"
+__version_9_0_reg = "VisualStudio\\9.0\\Setup\\VC"
+__version_9_0express_reg = "VCExpress\\9.0\\Setup\\VC"
+__version_10_0_reg = "VisualStudio\\10.0\\Setup\\VC"
+__version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC"
+__version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC"
+
+# Visual C++ Toolkit 2003 does not store its installation path in the registry.
+# The environment variable 'VCToolkitInstallDir' and the default installation
+# path will be checked instead.
+__version_7_1toolkit_path = 'Microsoft Visual C++ Toolkit 2003\\bin'
+__version_7_1toolkit_env = 'VCToolkitInstallDir'
+
+# Path to the folder containing "cl.exe" relative to the value of the
+# corresponding environment variable.
+__version_7_1toolkit_envpath = 'bin' ;
+#
+#
+# Auto-detect all the available msvc installations on the system.
+auto_detect_toolset_versions()
+
+# And finally trigger the actual Boost Build toolset registration.
+register_toolset()
diff --git a/tools/build/v2/tools/pch.py b/tools/build/v2/tools/pch.py
index 21d3db09df..71cb7166eb 100644
--- a/tools/build/v2/tools/pch.py
+++ b/tools/build/v2/tools/pch.py
@@ -29,6 +29,7 @@
# ;
from b2.build import type, feature, generators
+from b2.tools import builtin
type.register('PCH', ['pch'])
type.register('C_PCH', [], 'PCH')
@@ -48,7 +49,7 @@ class PchGenerator(generators.Generator):
from being run unless it's being used for a top-level PCH target.
"""
def action_class(self):
- return 'compile-action'
+ return builtin.CompileAction
def run(self, project, name, prop_set, sources):
if not name:
@@ -65,7 +66,7 @@ class PchGenerator(generators.Generator):
pass
else:
r = self.run_pch(project, name,
- prop_set.add_raw('<define>BOOST_BUILD_PCH_ENABLED'),
+ prop_set.add_raw(['<define>BOOST_BUILD_PCH_ENABLED']),
sources)
return generators.add_usage_requirements(
r, ['<define>BOOST_BUILD_PCH_ENABLED'])
@@ -74,10 +75,9 @@ class PchGenerator(generators.Generator):
def run_pch(self, project, name, prop_set, sources):
pass
-#FIXME: dummy-generator in builtins.jam needs to be ported.
# NOTE: requirements are empty, default pch generator can be applied when
# pch=off.
-###generators.register(
-### [ new dummy-generator pch.default-c-pch-generator : : C_PCH ] ;
-###generators.register
-### [ new dummy-generator pch.default-cpp-pch-generator : : CPP_PCH ] ;
+generators.register(builtin.DummyGenerator(
+ "pch.default-c-pch-generator", False, [], ['C_PCH'], []))
+generators.register(builtin.DummyGenerator(
+ "pch.default-cpp-pch-generator", False, [], ['CPP_PCH'], []))
diff --git a/tools/build/v2/tools/python.jam b/tools/build/v2/tools/python.jam
index 66f2aabec3..6c2073b788 100644
--- a/tools/build/v2/tools/python.jam
+++ b/tools/build/v2/tools/python.jam
@@ -1178,7 +1178,7 @@ class python-test-generator : generator
property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
- result = [ construct-result $(python) $(extensions) $(new-sources) :
+ return [ construct-result $(python) $(extensions) $(new-sources) :
$(project) $(name) : $(property-set) ] ;
}
}
diff --git a/tools/build/v2/tools/stage.jam b/tools/build/v2/tools/stage.jam
index 296e7558e4..36427447bf 100644
--- a/tools/build/v2/tools/stage.jam
+++ b/tools/build/v2/tools/stage.jam
@@ -263,7 +263,7 @@ class install-target-class : basic-target
}
}
DELETE_MODULE $(result) ;
- result = [ sequence.unique $(result2) ] ;
+ return [ sequence.unique $(result2) ] ;
}
# Returns true iff 'type' is subtype of some element of 'types-to-include'.
diff --git a/tools/build/v2/tools/stage.py b/tools/build/v2/tools/stage.py
index 25eccbe513..90d3c0f976 100644
--- a/tools/build/v2/tools/stage.py
+++ b/tools/build/v2/tools/stage.py
@@ -224,7 +224,7 @@ def symlink(name, project, source, ps):
return virtual_target.FileTarget(name, source.type(), project, a, exact=True)
def relink_file(project, source, ps):
- action = source.action()
+ action = source[0].action()
cloned_action = virtual_target.clone_action(action, project, "", ps)
targets = cloned_action.targets()
# We relink only on Unix, where exe or shared lib is always a single file.
diff --git a/tools/build/v2/tools/types/__init__.py b/tools/build/v2/tools/types/__init__.py
index f972b71495..9ee31d13a3 100644
--- a/tools/build/v2/tools/types/__init__.py
+++ b/tools/build/v2/tools/types/__init__.py
@@ -5,6 +5,7 @@ __all__ = [
'html',
'lib',
'obj',
+ 'preprocessed',
'rsp',
]
diff --git a/tools/build/v2/tools/types/cpp.py b/tools/build/v2/tools/types/cpp.py
index 7b56111c85..a6703255c6 100644
--- a/tools/build/v2/tools/types/cpp.py
+++ b/tools/build/v2/tools/types/cpp.py
@@ -5,6 +5,9 @@
from b2.build import type
def register ():
- type.register_type ('CPP', ['cpp', 'cxx', 'cc'])
+ type.register_type('CPP', ['cpp', 'cxx', 'cc'])
+ type.register_type('H', ['h'])
+ type.register_type('HPP', ['hpp'], 'H')
+ type.register_type('C', ['c'])
register ()
diff --git a/tools/build/v2/tools/types/preprocessed.py b/tools/build/v2/tools/types/preprocessed.py
new file mode 100644
index 0000000000..f591043347
--- /dev/null
+++ b/tools/build/v2/tools/types/preprocessed.py
@@ -0,0 +1,11 @@
+# Copyright David Abrahams 2004. Distributed under the Boost
+# Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+from b2.build import type
+
+def register ():
+ type.register_type('PREPROCESSED_C', ['i'], 'C')
+ type.register_type('PREPROCESSED_CPP', ['ii'], 'CPP')
+
+register ()
diff --git a/tools/build/v2/tools/unix.py b/tools/build/v2/tools/unix.py
index d409c2e460..34758f57b5 100644
--- a/tools/build/v2/tools/unix.py
+++ b/tools/build/v2/tools/unix.py
@@ -58,8 +58,8 @@ class UnixSearchedLibGenerator (builtin.SearchedLibGenerator):
def optional_properties (self):
return self.requirements ()
- def run (self, project, name, prop_set, sources, multiple):
- result = SearchedLibGenerator.run (project, name, prop_set, sources, multiple)
+ def run (self, project, name, prop_set, sources):
+ result = SearchedLibGenerator.run (project, name, prop_set, sources)
set_library_order (sources, prop_set, result)
@@ -69,10 +69,10 @@ class UnixPrebuiltLibGenerator (generators.Generator):
def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
- def run (self, project, name, prop_set, sources, multiple):
+ def run (self, project, name, prop_set, sources):
f = prop_set.get ('<file>')
set_library_order_aux (f, sources)
- return (f, sources)
+ return f + sources
### # The derived toolset must specify their own rules and actions.
# FIXME: restore?
diff --git a/tools/build/v2/util/doc.jam b/tools/build/v2/util/doc.jam
index a751558821..6e89d075ee 100644
--- a/tools/build/v2/util/doc.jam
+++ b/tools/build/v2/util/doc.jam
@@ -670,7 +670,7 @@ local rule extract-syntax (
while ! $(syntax) && ! [ MATCH "^[$(ws)]*(#)" : $(line) ] && $($(var))
{
local m = [ MATCH "^[$(ws)]*(.*)$" : $(line) ] ;
- if $(m) && ! $(m) = ""
+ if $(m)
{
syntax = $(m) ;
}
diff --git a/tools/quickbook/doc/1_6.qbk b/tools/quickbook/doc/1_6.qbk
index c3ca99c0a0..89c41f2ac0 100644
--- a/tools/quickbook/doc/1_6.qbk
+++ b/tools/quickbook/doc/1_6.qbk
@@ -278,4 +278,86 @@ html.
[endsect]
-[endsect] [/ Quickbok 1.6] \ No newline at end of file
+[endsect] [/ Quickbok 1.6]
+
+[section:1_7 Quickbook 1.7]
+
+[section:source_mode Source mode for single entities]
+
+1.7 introduces a new `!` element type for setting the source mode of a single
+entity without changing the source mode otherwise. This can be used for
+code blocks and other elements. For example:
+
+```
+[!c++]
+ void foo() {};
+
+[!python]``\`\`\`\ ``def foo():``\`\`\`\ ``
+```
+
+It can also be used to set the source mode for elements:
+
+```
+[!teletype][table
+ [[code][meaning]]
+ [[`+`][addition]]
+]
+```
+
+When used a section, it's only set for the section element, not the
+whole section.
+
+Currently it does support other syntactic entities such as paragraphs
+and lists. I'm not sure if it would be a good idea.
+
+[endsect]
+
+[section:callouts Callouts in code block]
+
+Currently callouts can only be used in code snippets. 1.7 add
+support in normal code blocks. The same syntax is used as in
+code snippets, the callout descriptions appear immediately
+after the code block.
+
+[endsect]
+
+[section:escaped_docinfo_attributes Escaped docbook in docinfo blocks]
+
+Quickbook docinfo attributes will probably never be as rich as docbook
+attributes so to allow more flexible markup, not supported by quickbook
+escaped docbook can be included in the docinfo block:
+
+```
+[article Some article
+[quickbook 1.7]
+'''<author>
+ <firstname>John</firstname>
+ <surname>Doe</surname>
+ <email>john.doe@example.com</email>
+</author>'''
+]
+```
+
+The escaped docbook is always placed at the end of the docinfo block,
+so it shouldn't be assumed that it will interleave the markup. A mixture
+of quickbook and docbook attributes for the same information will not work
+well.
+
+[endsect] [/escaped_docinfo_attributes]
+
+[section:templates_in_link_values Templates in link values]
+
+There's very premilinary support for calling templates in link values. A lot
+more work needs to be done, including:
+
+* Considering other places where templates could be called (e.g. images are
+ quite tricky, as templates could get confused with attributes, should
+ templates be callable from something like an element's id?).
+* Trimming spaces from the body of the template (which can cause surprising
+ results).
+* Checking that the contents of the template are appropriate for the context.
+ Possibly even using a different grammar.
+
+[endsect] [/templates_in_link_values]
+
+[endsect] [/ Quickbok 1.7]
diff --git a/tools/quickbook/doc/block.qbk b/tools/quickbook/doc/block.qbk
index f9da265b77..c6765131f7 100644
--- a/tools/quickbook/doc/block.qbk
+++ b/tools/quickbook/doc/block.qbk
@@ -14,7 +14,8 @@
[source-mode teletype]
]
-[section xinclude]
+[#quickbook.ref.xinclude]
+[section:xinclude xinclude]
You can include another XML file with:
@@ -27,7 +28,8 @@ reference section.
[endsect] [/xinclude]
-[section Paragraphs]
+[#quickbook.ref.paragraphs]
+[section:paragraphs Paragraphs]
Paragraphs start left-flushed and are terminated by two or more newlines. No
markup is needed for paragraphs. QuickBook automatically detects paragraphs from
@@ -36,10 +38,12 @@ the context. Block markups \[section, endsect, h1, h2, h3, h4, h5, h6, blurb,
[/ <-- There's a space here. Don't remove. this is intentianal, for testing]
This is a new paragraph...
-[endsect] [/Paragraphs]
+[endsect] [/paragraphs]
-[section Lists]
-[section Ordered lists]
+[#quickbook.ref.lists]
+[section:lists Lists]
+[#quickbook.ref.ordered_lists]
+[section:ordered_lists Ordered lists]
[pre
# One
@@ -53,8 +57,9 @@ will generate:
# Two
# Three
-[endsect] [/Ordered lists]
-[section List Hierarchies]
+[endsect] [/ordered_lists]
+[#quickbook.ref.list_hierarchies]
+[section:list_hierarchies List Hierarchies]
List hierarchies are supported. Example:
@@ -86,8 +91,9 @@ will generate:
# Four.a.ii
# Five
-[endsect] [/List Hierarchies]
-[section Long List Lines]
+[endsect] [/list_hierarchies]
+[#quickbook.ref.long_list_lines]
+[section:long_list_lines Long List Lines]
Long lines will be wrapped appropriately. Example:
@@ -109,8 +115,9 @@ Long lines will be wrapped appropriately. Example:
A very long item. A very long item. A very long item.
# A short item.
-[endsect] [/Long list lines]
-[section Unordered lists]
+[endsect] [/long_list_lines]
+[#quickbook.ref.unordered_lists]
+[section:unordered_lists Unordered lists]
```
* First
@@ -124,8 +131,9 @@ will generate:
* Second
* Third
-[endsect] [/Unordered lists]
-[section Mixed lists]
+[endsect] [/unordered_lists]
+[#quickbook.ref.mixed_lists]
+[section:mixed_lists Mixed lists]
Mixed lists (ordered and unordered) are supported. Example:
@@ -181,10 +189,11 @@ will generate:
* 2.b.2.a
* 2.b.2.b
-[endsect] [/Mixed lists]
-[endsect] [/Lists]
+[endsect] [/mixed_lists]
+[endsect] [/lists]
-[section Code]
+[#quickbook.ref.code]
+[section:code Code]
Preformatted code starts with a space or a tab. The code will be
syntax highlighted according to the current __source_mode__:
@@ -227,8 +236,9 @@ Generates:
using __boost__::__array__;
-[endsect] [/Code]
+[endsect] [/code]
+[#quickbook.ref.escape_back]
[section:escape_back Escaping Back To QuickBook]
Inside code, code blocks and inline code, QuickBook does not allow any
@@ -252,9 +262,10 @@ Will generate:
When escaping from code to QuickBook, only phrase level markups are
allowed. Block level markups like lists, tables etc. are not allowed.
-[endsect] [/Escaping back to quickbook]
+[endsect] [/escaping_back_to_quickbook]
-[section Preformatted]
+[#quickbook.ref.preformatted]
+[section:preformatted Preformatted]
Sometimes, you don't want some preformatted text to be parsed as source code. In such
cases, use the [^\[pre ... \]] markup block.
@@ -288,9 +299,10 @@ Some *preformatted* text Some *preformatted* text
Notice that unlike Code, phrase markup such as font style is still permitted
inside =pre= blocks.
-[endsect] [/Preformatted]
+[endsect] [/preformatted]
-[section Blockquote]
+[#quickbook.ref.blockquote]
+[section:blockquote Blockquote]
[pre
'''[:sometext...]'''
@@ -298,9 +310,10 @@ inside =pre= blocks.
[:Indents the paragraph. This applies to one paragraph only.]
-[endsect] [/Blockquote]
+[endsect] [/blockquote]
-[section Admonitions]
+[#quickbook.ref.admonitions]
+[section:admonitions Admonitions]
```
[note This is a note]
@@ -322,9 +335,10 @@ These are the only admonitions supported by __docbook__. So,
for example [^\[information This is some information\]] is unlikely
to produce the desired effect.
-[endsect] [/Admonitions]
+[endsect] [/admonitions]
-[section Headings]
+[#quickbook.ref.headings]
+[section:headings Headings]
```
[h1 Heading 1]
@@ -356,9 +370,10 @@ For example: Heading 1 in section Section 2 will be normalized to
to link to them. See __anchor_links__ and __section__ for more info.
-[endsect] [/Headings]
+[endsect] [/headings]
-[section Generic Heading]
+[#quickbook.ref.generic_heading]
+[section:generic_heading Generic Heading]
In cases when you don't want to care about the heading level (1 to 6), you
can use the /Generic Heading/:
@@ -402,9 +417,10 @@ at will without any extra work to ensure correct heading levels. In fact,
with /section/ and /heading/, you have all you need. /h1/../h6/ becomes
redundant. /h1/../h6/ might be deprecated in the future.
-[endsect] [/Generic Heading]
+[endsect] [/generic_heading]
-[section Macros]
+[#quickbook.ref.macros]
+[section:macros Macros]
```
[def macro_identifier some text]
@@ -455,9 +471,10 @@ will generate this:
Hi __spirit__ :-)
-[endsect] [/Macros]
+[endsect] [/macros]
-[section Predefined Macros]
+[#quickbook.ref.predefined_macros]
+[section:predefined_macros Predefined Macros]
Quickbook has some predefined macros that you can already use.
@@ -468,9 +485,10 @@ Quickbook has some predefined macros that you can already use.
[[[^\__FILENAME__]][Quickbook source filename] [__FILENAME__]]
]
-[endsect] [/Predefined Macros]
+[endsect] [/predefined_macros]
-[section Templates]
+[#quickbook.ref.templates]
+[section:templates Templates]
Templates provide a more versatile text substitution mechanism. Templates
come in handy when you need to create parameterizable, multi-line,
@@ -496,6 +514,7 @@ Hi, my name is [name]. I am [age] years old. I am a [what].
]
+[#quickbook.ref.template_identifier]
[heading Template Identifier]
Template identifiers can either consist of:
@@ -513,7 +532,7 @@ alphanumeric characters or the underscore. This is similar to your typical
C/C++ identifier.
A template formal argument temporarily hides a template of the same name at
-the point where the [link quickbook.syntax.block.templates.template_expansion
+the point where the [link quickbook.ref.template_expansion
template is expanded]. Note that the body of the [^person] template above
refers to [^name] [^age] and [^what] as [^\[name\]] [^\[age\]] and
[^\[what\]]. [^name] [^age] and [^what] are actually templates that exist
@@ -620,7 +639,7 @@ Some squiggles...[*[alpha][beta]]
The difference with macros are
-* The explicit [link quickbook.syntax.block.templates.template_expansion
+* The explicit [link quickbook.ref.template_expansion
template expansion syntax]. This is an advantage because, now, we don't
have to use obscure naming conventions like double underscores (e.g.
\_\_alpha\_\_) to avoid unwanted
@@ -729,7 +748,7 @@ With templates, one of our objectives is to allow us to rewrite QuickBook
in QuickBook (as a qbk library). For that to happen, we need to accommodate
single character punctuation templates which are fairly common in
QuickBook. You might have noticed that single character punctuations are
-allowed as [link quickbook.syntax.block.templates.template_identifier
+allowed as [link quickbook.ref.template_identifier
template identifiers]. Example:
```
@@ -748,9 +767,10 @@ We will have:
<hey>baz</hey>
]
-[endsect] [/Templates]
+[endsect] [/templates]
-[section Blurbs]
+[#quickbook.ref.blurbs]
+[section:blurbs Blurbs]
```
[blurb ``\:-)`` [*An eye catching advertisement or note...]
@@ -772,12 +792,13 @@ will generate this:
(EBNF) completely in C++.
]
-[note Prefer [link quickbook.syntax.block.admonitions admonitions] wherever
+[note Prefer [link quickbook.ref.admonitions admonitions] wherever
appropriate.]
-[endsect] [/Blurbs]
+[endsect] [/blurbs]
-[section Tables]
+[#quickbook.ref.tables]
+[section:tables Tables]
```
[table:id A Simple Table
@@ -899,9 +920,10 @@ Here's how to have preformatted blocks of code in a table cell:
]
]
-[endsect] [/Tables]
+[endsect] [/tables]
-[section Variable Lists]
+[#quickbook.ref.variable_lists]
+[section:variable_lists Variable Lists]
```
[variablelist A Variable List
@@ -932,9 +954,10 @@ only 2 "columns" are allowed. The first column contains the terms, and
the second column contains the definitions. Those familiar with HTML
will recognize this as a "definition list".
-[endsect] [/Variable Lists]
+[endsect] [/variable_lists]
-[section Include]
+[#quickbook.ref.include]
+[section:include Include]
You can include one QuickBook file from another. The syntax is simply:
@@ -963,9 +986,10 @@ for instance, if there is a top section in someother.qbk named "Intro", the
named anchor for that section will be "someid.intro", and you can link to
it with [^\[link someid.intro The Intro\]].
-[endsect] [/Include]
+[endsect] [/include]
-[section Import]
+[#quickbook.ref.import]
+[section:import Import]
When documenting code, you'd surely need to present code from actual source
files. While it is possible to copy some code and paste them in your QuickBook
@@ -1110,4 +1134,4 @@ Example:
See the actual code here: [@boost:/tools/quickbook/test/stub.cpp]
-[endsect] [/Import]
+[endsect] [/import]
diff --git a/tools/quickbook/doc/phrase.qbk b/tools/quickbook/doc/phrase.qbk
index 613d730bc5..f6f8859798 100644
--- a/tools/quickbook/doc/phrase.qbk
+++ b/tools/quickbook/doc/phrase.qbk
@@ -14,7 +14,8 @@
[source-mode teletype]
]
-[section Font Styles]
+[#quickbook.ref.font_styles]
+[section:font_styles Font Styles]
```
['italic], [*bold], [_underline], [^teletype], [-strikethrough]
@@ -34,9 +35,10 @@ will generate:
[*['bold-italic]]
-[endsect] [/Font Styles]
+[endsect] [/font_styles]
-[section Replaceable]
+[#quickbook.ref.replaceable]
+[section:replaceable Replaceable]
When you want content that may or must be replaced by the user, use the syntax:
@@ -48,9 +50,10 @@ This will generate:
[~replacement]
-[endsect] [/Replaceable]
+[endsect] [/replaceable]
-[section Quotations]
+[#quickbook.ref.quotations]
+[section:quotations Quotations]
```
["A question that sometimes drives me hazy: am I or are the others crazy?]--Einstein
@@ -76,9 +79,10 @@ will generate:
["Here's the rule for bargains: ["Do other men, for they would do you.]
That's the true business precept.]
-[endsect] [/Quotations]
+[endsect] [/quotations]
-[section Simple formatting]
+[#quickbook.ref.simple_formatting]
+[section:simple_formatting Simple formatting]
Simple markup for formatting text, common in many applications, is now supported:
@@ -159,9 +163,10 @@ Yes sir, yes sir, three bags full!
One for the master, one for the dame,
And one for the little boy who lives down the lane.
-[endsect] [/Simple Formatting]
+[endsect] [/simple_formatting]
-[section Inline code]
+[#quickbook.ref.inline_code]
+[section:inline_code Inline code]
Inlining code in paragraphs is quite common when writing C++ documentation. We
provide a very simple markup for this. For example, this:
@@ -179,9 +184,10 @@ syntax highlighted.
single quote: `"'"`. Note too that [^\`some code\`] is preferred over
`[^some code]`. ]
-[endsect] [/Inline Code]
+[endsect] [/inline_code]
-[section Code blocks]
+[#quickbook.ref.code_blocks]
+[section:code_blocks Code blocks]
Preformatted code simply starts with a space or a tab (See __code__).
However, such a simple syntax cannot be used as phrase elements in lists
@@ -235,9 +241,10 @@ will generate:
[teletype]
-[endsect] [/Code blocks]
+[endsect] [/code_blocks]
-[section Source Mode]
+[#quickbook.ref.source_mode]
+[section:source_mode Source Mode]
If a document contains more than one type of source code then the source
mode may be changed dynamically as the document is processed. All QuickBook
@@ -270,10 +277,10 @@ C++ comment `// looks like this` whereas a Python comment [python]
[note The source mode strings are lowercase.]
-[endsect] [/Source Mode]
+[endsect] [/source_mode]
-[#ref-line-break]
-[section line-break]
+[#quickbook.ref.line_break]
+[section:line_break line-break]
```
[br]
@@ -283,9 +290,10 @@ C++ comment `// looks like this` whereas a Python comment [python]
there might be problems, especially when using an alternative docbook
processor.]
-[endsect] [/Line break]
+[endsect] [/line_break]
-[section Anchors]
+[#quickbook.ref.anchors]
+[section:anchors Anchors]
```
[#named_anchor]
@@ -299,9 +307,10 @@ These anchors are global and can be accessed from anywhere in the
quickbook documentation. Be careful to avoid clashes with anchors in
other sections.
-[endsect] [/Anchors]
+[endsect] [/anchors]
-[section Links]
+[#quickbook.ref.links]
+[section:links Links]
```
[@http://www.boost.org this is [*boost's] website....]
@@ -339,9 +348,10 @@ will generate: [@boost:/libs/spirit/index.html the Boost.Spirit documentation]
Note that this is only available when using BoostBook, and only for links
- it can't be used for images.
-[endsect] [/Links]
+[endsect] [/links]
-[section Anchor links]
+[#quickbook.ref.anchor_links]
+[section:anchor_links Anchor links]
You can link within a document using:
@@ -351,9 +361,10 @@ You can link within a document using:
See sections __section__ and __heading__ for more info.
-[endsect] [/Anchor links]
+[endsect] [/anchor_links]
-[section refentry links]
+[#quickbook.ref.refentry_links]
+[section:refentry_links refentry links]
In addition, you can link internally to an XML refentry like:
@@ -372,8 +383,9 @@ automatically be the refentry. Example:
This gets converted into [^<link linkend="xml.refentry">xml.refentry</link>].
-[endsect] [/refentry links]
+[endsect] [/refentry_links]
+[#quickbook.ref.code_links]
[section:code_links Code Links]
If you want to link to a function, class, member, enum, concept, global, or header in
@@ -400,9 +412,10 @@ Example:
would have "boost::bar::baz" as the link text.
-[endsect] [/Code Links]
+[endsect] [/code_links]
-[section Escape]
+[#quickbook.ref.escape]
+[section:escape Escape]
The escape mark-up is used when we don't want to do any processing.
@@ -427,9 +440,10 @@ Escaping allows us to pass XML markup to __boostbook__ or __docbook__. For examp
[important Be careful when using the escape. The text must conform to
__boostbook__/__docbook__ syntax.]
-[endsect] [/Escape]
+[endsect] [/escape]
-[section Single char escape]
+[#quickbook.ref.single_char_escape]
+[section:single_char_escape Single char escape]
The backslash may be used to escape a single punctuation character. The
punctuation immediately after the backslash is passed without any processing.
@@ -439,15 +453,16 @@ For example, how do you escape the triple quote? Simple: [^\\'\\'\\']
`\n` has a special meaning. It is used to generate line breaks.
-[warning `\n` is now deprecated, use [link ref-line-break `[br]`]
+[warning `\n` is now deprecated, use [link quickbook.ref.line_break `[br]`]
instead. Although, use it sparingly as it can generated invalid docbook]
The escaped space: `\ ` also has a special meaning. The escaped space is removed
from the output.
-[endsect] [/Single char escape]
+[endsect] [/single_char_escape]
-[section Unicode escape]
+[#quickbook.ref.unicode_escape]
+[section:unicode_escape Unicode escape]
You can enter any 16-bit unicode character by using `\u` followed by its 4 digit
hexadecimal code, or a 32-bit character by using `\U` followed by an 8 digit
@@ -463,9 +478,10 @@ will generate:
\u03B1 + \u03B2
]
-[endsect] [/Unicode escape]
+[endsect] [/unicode_escape]
-[section Images]
+[#quickbook.ref.images]
+[section:images Images]
```
[$image.jpg]
@@ -479,9 +495,10 @@ DocBook imagedata attributes]:
[$image.jpg [width 200in] [height 200in]]
```
-[endsect] [/Images]
+[endsect] [/images]
-[section Footnotes]
+[#quickbook.ref.footnotes]
+[section:footnotes Footnotes]
As of version 1.3, QuickBook supports footnotes. Just put the text of the
footnote in a `[footnote]` block, and the text will be put at the bottom
@@ -493,9 +510,10 @@ of the current page. For example, this:
will generate this[footnote A sample footnote].
-[endsect] [/Footnotes]
+[endsect] [/footnotes]
-[section Macro Expansion]
+[#quickbook.ref.macro_expansion]
+[section:macro_expansion Macro Expansion]
```
__a_macro_identifier__
@@ -503,9 +521,10 @@ __a_macro_identifier__
See __macros__ for details.
-[endsect] [/Macro Expansion]
+[endsect] [/macro_expansion]
-[section Template Expansion]
+[#quickbook.ref.template_expansion]
+[section:template_expansion Template Expansion]
```
[a_template_identifier]
@@ -513,8 +532,9 @@ See __macros__ for details.
See __templates__ for details.
-[endsect] [/Template Expansion]
+[endsect] [/template_expansion]
+[#quickbook.ref.cond]
[section:cond Conditional Generation]
Like C++ `#ifdef`, you can generate phrases depending on the presence of
@@ -543,4 +563,4 @@ And try again:
Yes!
-[endsect] [/Condition Generation]
+[endsect] [/cond]
diff --git a/tools/quickbook/doc/quickbook.qbk b/tools/quickbook/doc/quickbook.qbk
index da3f9a8fbe..ea988f9e2f 100644
--- a/tools/quickbook/doc/quickbook.qbk
+++ b/tools/quickbook/doc/quickbook.qbk
@@ -37,49 +37,49 @@
[def __boostbook__ [@http://www.boost.org/doc/html/boostbook.html BoostBook]]
[def __docbook__ [@http://www.docbook.org/ DocBook]]
-[def __comments__ [link quickbook.syntax.comments Comments]]
+[def __comments__ [link quickbook.ref.comments Comments]]
-[def __font_styles__ [link quickbook.syntax.phrase.font_styles Font Styles]]
-[def __quotations__ [link quickbook.syntax.phrase.quotations Quotations]]
-[def __replaceable__ [link quickbook.syntax.phrase.replaceable Replaceble]]
-[def __simple_formatting__ [link quickbook.syntax.phrase.simple_formatting Simple formatting]]
-[def __inline_code__ [link quickbook.syntax.phrase.inline_code Inline code]]
-[def __code_blocks__ [link quickbook.syntax.phrase.code_blocks Code blocks]]
-[def __source_mode__ [link quickbook.syntax.phrase.source_mode Source Mode]]
-[def __line_break__ [link quickbook.syntax.phrase.line_break line-break]]
-[def __anchors__ [link quickbook.syntax.phrase.anchors Anchors]]
-[def __links__ [link quickbook.syntax.phrase.links Links]]
-[def __anchor_links__ [link quickbook.syntax.phrase.anchor_links Anchor links]]
-[def __refentry_links__ [link quickbook.syntax.phrase.refentry_links refentry links]]
-[def __code_links__ [link quickbook.syntax.phrase.code_links function, class, member, enum, macro, concept or header links]]
-[def __escape__ [link quickbook.syntax.phrase.escape Escape]]
-[def __single_char_escape__ [link quickbook.syntax.phrase.single_char_escape Single char escape]]
-[def __images__ [link quickbook.syntax.phrase.images Images]]
-[def __cond__ [link quickbook.syntax.phrase.cond Conditional Generation]]
+[def __font_styles__ [link quickbook.ref.font_styles Font Styles]]
+[def __quotations__ [link quickbook.ref.quotations Quotations]]
+[def __replaceable__ [link quickbook.ref.replaceable Replaceble]]
+[def __simple_formatting__ [link quickbook.ref.simple_formatting Simple formatting]]
+[def __inline_code__ [link quickbook.ref.inline_code Inline code]]
+[def __code_blocks__ [link quickbook.ref.code_blocks Code blocks]]
+[def __source_mode__ [link quickbook.ref.source_mode Source Mode]]
+[def __line_break__ [link quickbook.ref.line_break line-break]]
+[def __anchors__ [link quickbook.ref.anchors Anchors]]
+[def __links__ [link quickbook.ref.links Links]]
+[def __anchor_links__ [link quickbook.ref.anchor_links Anchor links]]
+[def __refentry_links__ [link quickbook.ref.refentry_links refentry links]]
+[def __code_links__ [link quickbook.ref.code_links function, class, member, enum, macro, concept or header links]]
+[def __escape__ [link quickbook.ref.escape Escape]]
+[def __single_char_escape__ [link quickbook.ref.single_char_escape Single char escape]]
+[def __images__ [link quickbook.ref.images Images]]
+[def __cond__ [link quickbook.ref.cond Conditional Generation]]
-[def __document__ [link quickbook.syntax.structure.docinfo Document]]
-[def __section__ [link quickbook.syntax.structure.section Section]]
-[def __xinclude__ [link quickbook.syntax.block.xinclude xinclude]]
-[def __paragraphs__ [link quickbook.syntax.block.paragraphs Paragraphs]]
-[def __ordered_lists__ [link quickbook.syntax.block.lists.ordered_lists Ordered lists]]
-[def __list_hierarchies__ [link quickbook.syntax.block.lists.list_hierarchies List Hierarchies]]
-[def __long_list_lines__ [link quickbook.syntax.block.lists.long_list_lines Long List Lines]]
-[def __unordered_lists__ [link quickbook.syntax.block.lists.unordered_lists Unordered lists]]
-[def __mixed_lists__ [link quickbook.syntax.block.lists.mixed_lists Mixed lists]]
-[def __code__ [link quickbook.syntax.block.code Code]]
-[def __escape_back__ [link quickbook.syntax.block.escape_back Escaping Back To QuickBook]]
-[def __preformatted__ [link quickbook.syntax.block.preformatted Preformatted]]
-[def __blockquote__ [link quickbook.syntax.block.blockquote Blockquote]]
-[def __heading__ [link quickbook.syntax.block.headings Heading]]
-[def __macros__ [link quickbook.syntax.block.macros Macros]]
-[def __templates__ [link quickbook.syntax.block.templates Templates]]
-[def __predefined_macros__ [link quickbook.syntax.block.predefined_macros Predefined Macros]]
-[def __blurbs__ [link quickbook.syntax.block.blurbs Blurbs]]
-[def __admonitions__ [link quickbook.syntax.block.admonitions Admonitions]]
-[def __tables__ [link quickbook.syntax.block.tables Tables]]
-[def __variable_lists__ [link quickbook.syntax.block.variable_lists Variable Lists]]
-[def __include__ [link quickbook.syntax.block.include Include]]
-[def __import__ [link quickbook.syntax.block.import Import]]
+[def __document__ [link quickbook.ref.docinfo Document]]
+[def __section__ [link quickbook.ref.section Section]]
+[def __xinclude__ [link quickbook.ref.xinclude xinclude]]
+[def __paragraphs__ [link quickbook.ref.paragraphs Paragraphs]]
+[def __ordered_lists__ [link quickbook.ref.ordered_lists Ordered lists]]
+[def __list_hierarchies__ [link quickbook.ref.list_hierarchies List Hierarchies]]
+[def __long_list_lines__ [link quickbook.ref.long_list_lines Long List Lines]]
+[def __unordered_lists__ [link quickbook.ref.unordered_lists Unordered lists]]
+[def __mixed_lists__ [link quickbook.ref.mixed_lists Mixed lists]]
+[def __code__ [link quickbook.ref.code Code]]
+[def __escape_back__ [link quickbook.ref.escape_back Escaping Back To QuickBook]]
+[def __preformatted__ [link quickbook.ref.preformatted Preformatted]]
+[def __blockquote__ [link quickbook.ref.blockquote Blockquote]]
+[def __heading__ [link quickbook.ref.headings Heading]]
+[def __macros__ [link quickbook.ref.macros Macros]]
+[def __templates__ [link quickbook.ref.templates Templates]]
+[def __predefined_macros__ [link quickbook.ref.predefined_macros Predefined Macros]]
+[def __blurbs__ [link quickbook.ref.blurbs Blurbs]]
+[def __admonitions__ [link quickbook.ref.admonitions Admonitions]]
+[def __tables__ [link quickbook.ref.tables Tables]]
+[def __variable_lists__ [link quickbook.ref.variable_lists Variable Lists]]
+[def __include__ [link quickbook.ref.include Include]]
+[def __import__ [link quickbook.ref.import Import]]
[include introduction.qbk]
[include change_log.qbk]
diff --git a/tools/quickbook/doc/structure.qbk b/tools/quickbook/doc/structure.qbk
index 80e812c2f1..c9a4be9c33 100644
--- a/tools/quickbook/doc/structure.qbk
+++ b/tools/quickbook/doc/structure.qbk
@@ -26,7 +26,7 @@ quickbook allows you to use it now, it isn't recommended as it is
currently a work in progress and subject to change.
]
-[#ref-docinfo]
+[#quickbook.ref.docinfo]
[section:docinfo Document Info]
Every document must begin with a Document Info section, which looks something
@@ -73,6 +73,7 @@ So the documentation for the 'foo' library might start:
]
```
+[#quickbook.ref.attributes]
[section:attributes Document Info Attributes]
The document info block has a few different types of attributes.
@@ -145,6 +146,7 @@ that's just ignored by the style sheets.
[endsect] [/docinfo]
+[#quickbook.ref.section]
[section:section Sections]
Quickbook documents are structured using 'sections'. These are used
@@ -173,11 +175,12 @@ A sectioned document might look like:
```
Sections start with the `section` tag, and end with the `[endsect]` tag.
-(`[/...]` is a comment, [link quickbook.syntax.comments described later]).
+(`[/...]` is a comment, [link quickbook.ref.comments described later]).
Sections can be given an optional id:
```
+[#quickbook.ref.id]
[section:id The Section Title]
```
diff --git a/tools/quickbook/doc/syntax.qbk b/tools/quickbook/doc/syntax.qbk
index 2c3c41e465..5088278fc3 100644
--- a/tools/quickbook/doc/syntax.qbk
+++ b/tools/quickbook/doc/syntax.qbk
@@ -28,7 +28,8 @@ Phrases in each block cannot contain a block terminator. This way, syntax errors
such as un-matched closing brackets do not go haywire and corrupt anything past
a single block.
-[section Comments]
+[#quickbook.ref.comments]
+[section:comments Comments]
Can be placed anywhere.
@@ -50,5 +51,4 @@ Can be placed anywhere.
[/ for testing [*only ] ]
-[endsect] [/Comments]
-
+[endsect] [/comments]
diff --git a/tools/quickbook/src/Jamfile.v2 b/tools/quickbook/src/Jamfile.v2
index 9372559492..0c55c7ae8b 100644
--- a/tools/quickbook/src/Jamfile.v2
+++ b/tools/quickbook/src/Jamfile.v2
@@ -15,6 +15,8 @@ project quickbook
<toolset>gcc:<cflags>-g0
<toolset>darwin:<cflags>-g0
<toolset>msvc:<cflags>/wd4709
+ <toolset>gcc:<define>BOOST_DETAIL_CONTAINER_FWD
+ <toolset>darwin:<define>BOOST_DETAIL_CONTAINER_FWD
;
lib shell32 ;
@@ -24,7 +26,7 @@ exe quickbook
quickbook.cpp
actions.cpp
doc_info_actions.cpp
- actions_class.cpp
+ state.cpp
utils.cpp
files.cpp
string_ref.cpp
diff --git a/tools/quickbook/src/actions.cpp b/tools/quickbook/src/actions.cpp
index 4802893cb1..304663ffe1 100644
--- a/tools/quickbook/src/actions.cpp
+++ b/tools/quickbook/src/actions.cpp
@@ -12,8 +12,9 @@
#include <functional>
#include <vector>
#include <map>
-#include <boost/filesystem/v3/convenience.hpp>
-#include <boost/filesystem/v3/fstream.hpp>
+#include <set>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/range/distance.hpp>
#include <boost/range/algorithm/replace.hpp>
#include <boost/lexical_cast.hpp>
@@ -25,8 +26,8 @@
#include "utils.hpp"
#include "files.hpp"
#include "markups.hpp"
-#include "actions_class.hpp"
-#include "actions_state.hpp"
+#include "state.hpp"
+#include "state_save.hpp"
#include "grammar.hpp"
#include "input_path.hpp"
#include "block_tags.hpp"
@@ -35,17 +36,22 @@
namespace quickbook
{
- char const* quickbook_get_date = "__quickbook_get_date__";
- char const* quickbook_get_time = "__quickbook_get_time__";
-
- unsigned qbk_version_n = 0; // qbk_major_version * 100 + qbk_minor_version
-
namespace {
- void write_anchors(quickbook::actions& actions, collector& tgt)
+ void write_anchors(quickbook::state& state, collector& tgt)
{
- for(quickbook::actions::string_list::iterator
- it = actions.anchors.begin(),
- end = actions.anchors.end();
+ // TODO: This works but is a bit of an odd place to put it.
+ // Might need to redefine the purpose of this function.
+ if (!state.source_mode_next.empty()) {
+ detail::outwarn(state.source_mode_next.get_file(),
+ state.source_mode_next.get_position())
+ << "Temporary source mode unsupported here."
+ << std::endl;
+ state.source_mode_next = value();
+ }
+
+ for(quickbook::state::string_list::iterator
+ it = state.anchors.begin(),
+ end = state.anchors.end();
it != end; ++it)
{
tgt << "<anchor id=\"";
@@ -53,46 +59,52 @@ namespace quickbook
tgt << "\"/>";
}
- actions.anchors.clear();
+ state.anchors.clear();
}
- std::string add_anchor(quickbook::actions& actions,
+ std::string add_anchor(quickbook::state& state,
std::string const& id,
id_category::categories category =
id_category::explicit_anchor_id)
{
- std::string placeholder = actions.ids.add_anchor(id, category);
- actions.anchors.push_back(placeholder);
+ std::string placeholder = state.ids.add_anchor(id, category);
+ state.anchors.push_back(placeholder);
return placeholder;
}
}
- void explicit_list_action(quickbook::actions&, value);
- void header_action(quickbook::actions&, value);
- void begin_section_action(quickbook::actions&, value);
- void end_section_action(quickbook::actions&, value, string_iterator);
- void block_action(quickbook::actions&, value);
- void block_empty_action(quickbook::actions&, value);
- void macro_definition_action(quickbook::actions&, value);
- void template_body_action(quickbook::actions&, value);
- void variable_list_action(quickbook::actions&, value);
- void table_action(quickbook::actions&, value);
- void xinclude_action(quickbook::actions&, value);
- void include_action(quickbook::actions&, value, string_iterator);
- void image_action(quickbook::actions&, value);
- void anchor_action(quickbook::actions&, value);
- void link_action(quickbook::actions&, value);
- void phrase_action(quickbook::actions&, value);
- void role_action(quickbook::actions&, value);
- void footnote_action(quickbook::actions&, value);
- void raw_phrase_action(quickbook::actions&, value);
- void source_mode_action(quickbook::actions&, value);
- void do_template_action(quickbook::actions&, value, string_iterator);
+ bool quickbook_range::in_range() const {
+ return qbk_version_n >= lower && qbk_version_n < upper;
+ }
+
+ void explicit_list_action(quickbook::state&, value);
+ void header_action(quickbook::state&, value);
+ void begin_section_action(quickbook::state&, value);
+ void end_section_action(quickbook::state&, value, string_iterator);
+ void block_action(quickbook::state&, value);
+ void block_empty_action(quickbook::state&, value);
+ void macro_definition_action(quickbook::state&, value);
+ void template_body_action(quickbook::state&, value);
+ void variable_list_action(quickbook::state&, value);
+ void table_action(quickbook::state&, value);
+ void xinclude_action(quickbook::state&, value);
+ void include_action(quickbook::state&, value, string_iterator);
+ void image_action(quickbook::state&, value);
+ void anchor_action(quickbook::state&, value);
+ void link_action(quickbook::state&, value);
+ void phrase_action(quickbook::state&, value);
+ void role_action(quickbook::state&, value);
+ void footnote_action(quickbook::state&, value);
+ void raw_phrase_action(quickbook::state&, value);
+ void source_mode_action(quickbook::state&, value);
+ void next_source_mode_action(quickbook::state&, value);
+ void code_action(quickbook::state&, value);
+ void do_template_action(quickbook::state&, value, string_iterator);
void element_action::operator()(parse_iterator first, parse_iterator) const
{
- value_consumer values = actions.values.release();
- if(!values.check() || !actions.conditional) return;
+ value_consumer values = state.values.release();
+ if(!values.check() || !state.conditional) return;
value v = values.consume();
values.finish();
@@ -100,7 +112,7 @@ namespace quickbook
{
case block_tags::ordered_list:
case block_tags::itemized_list:
- return explicit_list_action(actions, v);
+ return explicit_list_action(state, v);
case block_tags::generic_heading:
case block_tags::heading1:
case block_tags::heading2:
@@ -108,11 +120,11 @@ namespace quickbook
case block_tags::heading4:
case block_tags::heading5:
case block_tags::heading6:
- return header_action(actions, v);
+ return header_action(state, v);
case block_tags::begin_section:
- return begin_section_action(actions, v);
+ return begin_section_action(state, v);
case block_tags::end_section:
- return end_section_action(actions, v, first.base());
+ return end_section_action(state, v, first.base());
case block_tags::blurb:
case block_tags::preformatted:
case block_tags::blockquote:
@@ -122,26 +134,26 @@ namespace quickbook
case block_tags::note:
case block_tags::tip:
case block_tags::block:
- return block_action(actions,v);
+ return block_action(state,v);
case block_tags::hr:
- return block_empty_action(actions,v);
+ return block_empty_action(state,v);
case block_tags::macro_definition:
- return macro_definition_action(actions,v);
+ return macro_definition_action(state,v);
case block_tags::template_definition:
- return template_body_action(actions,v);
+ return template_body_action(state,v);
case block_tags::variable_list:
- return variable_list_action(actions, v);
+ return variable_list_action(state, v);
case block_tags::table:
- return table_action(actions, v);
+ return table_action(state, v);
case block_tags::xinclude:
- return xinclude_action(actions, v);
+ return xinclude_action(state, v);
case block_tags::import:
case block_tags::include:
- return include_action(actions, v, first.base());
+ return include_action(state, v, first.base());
case phrase_tags::image:
- return image_action(actions, v);
+ return image_action(state, v);
case phrase_tags::anchor:
- return anchor_action(actions, v);
+ return anchor_action(state, v);
case phrase_tags::url:
case phrase_tags::link:
case phrase_tags::funcref:
@@ -152,7 +164,7 @@ namespace quickbook
case phrase_tags::headerref:
case phrase_tags::conceptref:
case phrase_tags::globalref:
- return link_action(actions, v);
+ return link_action(state, v);
case phrase_tags::bold:
case phrase_tags::italic:
case phrase_tags::underline:
@@ -160,19 +172,25 @@ namespace quickbook
case phrase_tags::strikethrough:
case phrase_tags::quote:
case phrase_tags::replaceable:
- return phrase_action(actions, v);
+ return phrase_action(state, v);
case phrase_tags::footnote:
- return footnote_action(actions, v);
+ return footnote_action(state, v);
case phrase_tags::escape:
- return raw_phrase_action(actions, v);
+ return raw_phrase_action(state, v);
case phrase_tags::role:
- return role_action(actions, v);
+ return role_action(state, v);
case source_mode_tags::cpp:
case source_mode_tags::python:
case source_mode_tags::teletype:
- return source_mode_action(actions, v);
+ return source_mode_action(state, v);
+ case code_tags::next_source_mode:
+ return next_source_mode_action(state, v);
+ case code_tags::code_block:
+ case code_tags::inline_code_block:
+ case code_tags::inline_code:
+ return code_action(state, v);
case template_tags::template_:
- return do_template_action(actions, v, first.base());
+ return do_template_action(state, v, first.base());
default:
break;
}
@@ -180,22 +198,22 @@ namespace quickbook
void break_action::operator()(parse_iterator first, parse_iterator) const
{
- write_anchors(actions, phrase);
+ write_anchors(state, phrase);
if(*first == '\\')
{
- detail::outwarn(actions.current_file, first.base())
+ detail::outwarn(state.current_file, first.base())
//<< "in column:" << pos.column << ", "
<< "'\\n' is deprecated, pleases use '[br]' instead" << ".\n";
}
- if(!actions.warned_about_breaks)
+ if(!state.warned_about_breaks)
{
- detail::outwarn(actions.current_file, first.base())
+ detail::outwarn(state.current_file, first.base())
<< "line breaks generate invalid boostbook "
"(will only note first occurrence).\n";
- actions.warned_about_breaks = true;
+ state.warned_about_breaks = true;
}
phrase << detail::get_markup(phrase_tags::break_mark).pre;
@@ -203,7 +221,7 @@ namespace quickbook
void error_message_action::operator()(parse_iterator first, parse_iterator last) const
{
- file_position const pos = actions.current_file->position_of(first.base());
+ file_position const pos = state.current_file->position_of(first.base());
std::string value(first, last);
std::string formatted_message = message;
@@ -211,91 +229,91 @@ namespace quickbook
boost::replace_all(formatted_message, "%c",
boost::lexical_cast<std::string>(pos.column));
- detail::outerr(actions.current_file->path, pos.line)
- << detail::utf8(formatted_message) << std::endl;
- ++actions.error_count;
+ detail::outerr(state.current_file->path, pos.line)
+ << formatted_message << std::endl;
+ ++state.error_count;
}
void error_action::operator()(parse_iterator first, parse_iterator /*last*/) const
{
- file_position const pos = actions.current_file->position_of(first.base());
+ file_position const pos = state.current_file->position_of(first.base());
- detail::outerr(actions.current_file->path, pos.line)
+ detail::outerr(state.current_file->path, pos.line)
<< "Syntax Error near column " << pos.column << ".\n";
- ++actions.error_count;
+ ++state.error_count;
}
- void block_action(quickbook::actions& actions, value block)
+ void block_action(quickbook::state& state, value block)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
detail::markup markup = detail::get_markup(block.get_tag());
value_consumer values = block;
- actions.out << markup.pre << values.consume().get_encoded() << markup.post;
+ state.out << markup.pre << values.consume().get_encoded() << markup.post;
values.finish();
}
- void block_empty_action(quickbook::actions& actions, value block)
+ void block_empty_action(quickbook::state& state, value block)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
detail::markup markup = detail::get_markup(block.get_tag());
- actions.out << markup.pre;
+ state.out << markup.pre;
}
- void phrase_action(quickbook::actions& actions, value phrase)
+ void phrase_action(quickbook::state& state, value phrase)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
detail::markup markup = detail::get_markup(phrase.get_tag());
value_consumer values = phrase;
- actions.phrase << markup.pre << values.consume().get_encoded() << markup.post;
+ state.phrase << markup.pre << values.consume().get_encoded() << markup.post;
values.finish();
}
- void role_action(quickbook::actions& actions, value role)
+ void role_action(quickbook::state& state, value role)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
value_consumer values = role;
- actions.phrase
+ state.phrase
<< "<phrase role=\"";
- detail::print_string(values.consume().get_quickbook(), actions.phrase.get());
- actions.phrase
+ detail::print_string(values.consume().get_quickbook(), state.phrase.get());
+ state.phrase
<< "\">"
<< values.consume().get_encoded()
<< "</phrase>";
values.finish();
}
- void footnote_action(quickbook::actions& actions, value phrase)
+ void footnote_action(quickbook::state& state, value phrase)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
value_consumer values = phrase;
- actions.phrase
+ state.phrase
<< "<footnote id=\""
- << actions.ids.add_id("f", id_category::numbered)
+ << state.ids.add_id("f", id_category::numbered)
<< "\"><para>"
<< values.consume().get_encoded()
<< "</para></footnote>";
values.finish();
}
- void raw_phrase_action(quickbook::actions& actions, value phrase)
+ void raw_phrase_action(quickbook::state& state, value phrase)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
detail::markup markup = detail::get_markup(phrase.get_tag());
- actions.phrase << markup.pre << phrase.get_quickbook() << markup.post;
+ state.phrase << markup.pre << phrase.get_quickbook() << markup.post;
}
void paragraph_action::operator()() const
{
std::string str;
- actions.phrase.swap(str);
+ state.phrase.swap(str);
std::string::const_iterator
pos = str.begin(),
@@ -305,53 +323,61 @@ namespace quickbook
if(pos != end) {
detail::markup markup = detail::get_markup(block_tags::paragraph);
- actions.out << markup.pre << str;
- write_anchors(actions, actions.out);
- actions.out << markup.post;
+ state.out << markup.pre << str;
+ write_anchors(state, state.out);
+ state.out << markup.post;
}
}
void list_item_action::operator()() const
{
+ // Be careful as this is sometimes called in the wrong place
+ // for markup such as:
+ //
+ // * A
+ // [endsect]
+ //
+ // This action is called before [endsect] (to end the list item)
+ // and then also after it due to the way the parser works.
std::string str;
- actions.phrase.swap(str);
- actions.out << str;
- write_anchors(actions, actions.out);
+ state.phrase.swap(str);
+ state.out << str;
+ write_anchors(state, state.out);
}
void phrase_end_action::operator()() const
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
}
namespace {
- void write_bridgehead(quickbook::actions& actions, int level,
+ void write_bridgehead(quickbook::state& state, int level,
std::string const& str, std::string const& id, bool self_link)
{
if (self_link && !id.empty())
{
- actions.out << "<bridgehead renderas=\"sect" << level << "\"";
- actions.out << " id=\"";
- actions.out << actions.ids.add_id("h", id_category::numbered);
- actions.out << "\">";
- actions.out << "<phrase id=\"" << id << "\"/>";
- actions.out << "<link linkend=\"" << id << "\">";
- actions.out << str;
- actions.out << "</link>";
- actions.out << "</bridgehead>";
+ state.out << "<bridgehead renderas=\"sect" << level << "\"";
+ state.out << " id=\"";
+ state.out << state.ids.add_id("h", id_category::numbered);
+ state.out << "\">";
+ state.out << "<phrase id=\"" << id << "\"/>";
+ state.out << "<link linkend=\"" << id << "\">";
+ state.out << str;
+ state.out << "</link>";
+ state.out << "</bridgehead>";
}
else
{
- actions.out << "<bridgehead renderas=\"sect" << level << "\"";
- if(!id.empty()) actions.out << " id=\"" << id << "\"";
- actions.out << ">";
- actions.out << str;
- actions.out << "</bridgehead>";
+ state.out << "<bridgehead renderas=\"sect" << level << "\"";
+ if(!id.empty()) state.out << " id=\"" << id << "\"";
+ state.out << ">";
+ state.out << str;
+ state.out << "</bridgehead>";
}
}
}
- void header_action(quickbook::actions& actions, value heading_list)
+ void header_action(quickbook::state& state, value heading_list)
{
value_consumer values = heading_list;
@@ -364,7 +390,7 @@ namespace quickbook
if (generic)
{
- level = actions.ids.section_level() + 1;
+ level = state.ids.section_level() + 1;
// We need to use a heading which is one greater
// than the current.
if (level > 6 ) // The max is h6, clip it if it goes
@@ -375,51 +401,51 @@ namespace quickbook
level = heading_list.get_tag() - block_tags::heading1 + 1;
}
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
if (!element_id.empty())
{
- std::string anchor = actions.ids.add_id(
+ std::string anchor = state.ids.add_id(
element_id.get_quickbook(),
id_category::explicit_id);
- write_bridgehead(actions, level,
+ write_bridgehead(state, level,
content.get_encoded(), anchor, self_linked_headers);
}
- else if (!generic && actions.ids.compatibility_version() < 103) // version 1.2 and below
+ else if (!generic && state.ids.compatibility_version() < 103) // version 1.2 and below
{
// This generates the old id style if both the interpreting
// version and the generation version are less then 103u.
- std::string anchor = actions.ids.old_style_id(
+ std::string anchor = state.ids.old_style_id(
detail::make_identifier(
- actions.ids.replace_placeholders_with_unresolved_ids(
+ state.ids.replace_placeholders_with_unresolved_ids(
content.get_encoded())),
id_category::generated_heading);
- write_bridgehead(actions, level,
+ write_bridgehead(state, level,
content.get_encoded(), anchor, false);
}
else
{
- std::string anchor = actions.ids.add_id(
+ std::string anchor = state.ids.add_id(
detail::make_identifier(
- actions.ids.compatibility_version() >= 106 ?
+ state.ids.compatibility_version() >= 106 ?
content.get_quickbook() :
- actions.ids.replace_placeholders_with_unresolved_ids(
+ state.ids.replace_placeholders_with_unresolved_ids(
content.get_encoded())
),
id_category::generated_heading);
- write_bridgehead(actions, level,
+ write_bridgehead(state, level,
content.get_encoded(), anchor, self_linked_headers);
}
}
void simple_phrase_action::operator()(char mark) const
{
- write_anchors(actions, out);
+ write_anchors(state, out);
int tag =
mark == '*' ? phrase_tags::bold :
@@ -431,7 +457,7 @@ namespace quickbook
assert(tag != 0);
detail::markup markup = detail::get_markup(tag);
- value_consumer values = actions.values.release();
+ value_consumer values = state.values.release();
value content = values.consume();
values.finish();
@@ -442,21 +468,21 @@ namespace quickbook
bool cond_phrase_push::start()
{
- value_consumer values = actions.values.release();
+ value_consumer values = state.values.release();
- saved_conditional = actions.conditional;
+ saved_conditional = state.conditional;
if (saved_conditional)
{
string_ref macro1 = values.consume().get_quickbook();
std::string macro(macro1.begin(), macro1.end());
- actions.conditional = find(actions.macro, macro.c_str());
+ state.conditional = find(state.macro, macro.c_str());
- if (!actions.conditional) {
- actions.phrase.push();
- actions.out.push();
- actions.anchors.swap(anchors);
+ if (!state.conditional) {
+ state.phrase.push();
+ state.out.push();
+ state.anchors.swap(anchors);
}
}
@@ -465,14 +491,14 @@ namespace quickbook
void cond_phrase_push::cleanup()
{
- if (saved_conditional && !actions.conditional)
+ if (saved_conditional && !state.conditional)
{
- actions.phrase.pop();
- actions.out.pop();
- actions.anchors.swap(anchors);
+ state.phrase.pop();
+ state.out.pop();
+ state.anchors.swap(anchors);
}
- actions.conditional = saved_conditional;
+ state.conditional = saved_conditional;
}
namespace {
@@ -494,64 +520,141 @@ namespace quickbook
}
}
- void actions::start_list(char mark)
+ void state::start_list(char mark)
{
write_anchors(*this, out);
assert(mark == '*' || mark == '#');
out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
}
- void actions::end_list(char mark)
+ void state::end_list(char mark)
{
write_anchors(*this, out);
assert(mark == '*' || mark == '#');
out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
}
- void actions::start_list_item()
+ void state::start_list_item()
{
out << "<listitem><simpara>";
write_anchors(*this, out);
}
- void actions::end_list_item()
+ void state::end_list_item()
{
write_anchors(*this, out);
out << "</simpara></listitem>";
}
- void explicit_list_action(quickbook::actions& actions, value list)
+ namespace
+ {
+ bool parse_template(value const&, quickbook::state& state);
+ }
+
+ void state::start_callouts()
+ {
+ ++callout_depth;
+ }
+
+ std::string state::add_callout(value v)
+ {
+ std::string callout_id1 = ids.add_id("c", id_category::numbered);
+ std::string callout_id2 = ids.add_id("c", id_category::numbered);
+
+ callouts.insert(encoded_value(callout_id1));
+ callouts.insert(encoded_value(callout_id2));
+ callouts.insert(v);
+
+ std::string code;
+ code += "<co id=\"" + callout_id1 + "\" ";
+ code += "linkends=\"" + callout_id2 + "\" />";
+
+ return code;
+ }
+
+ std::string state::end_callouts()
{
- write_anchors(actions, actions.out);
+ assert(callout_depth > 0);
+ std::string block;
+
+ --callout_depth;
+ if (callout_depth > 0) return block;
+
+ value_consumer c = callouts.release();
+ if (!c.check()) return block;
+
+ block += "<calloutlist>";
+ while (c.check())
+ {
+ std::string callout_id1 = c.consume().get_encoded();
+ std::string callout_id2 = c.consume().get_encoded();
+ value callout_body = c.consume();
+
+ std::string callout_value;
+
+ {
+ template_state state(*this);
+ ++template_depth;
+
+ bool r = parse_template(callout_body, *this);
+
+ if(!r)
+ {
+ detail::outerr(callout_body.get_file(), callout_body.get_position())
+ << "Expanding callout." << std::endl
+ << "------------------begin------------------" << std::endl
+ << callout_body.get_quickbook()
+ << std::endl
+ << "------------------end--------------------" << std::endl
+ ;
+ ++error_count;
+ }
+
+ out.swap(callout_value);
+ }
+
+ block += "<callout arearefs=\"" + callout_id1 + "\" ";
+ block += "id=\"" + callout_id2 + "\">";
+ block += callout_value;
+ block += "</callout>";
+ }
+ block += "</calloutlist>";
+
+ return block;
+ }
+
+ void explicit_list_action(quickbook::state& state, value list)
+ {
+ write_anchors(state, state.out);
detail::markup markup = detail::get_markup(list.get_tag());
- actions.out << markup.pre;
+ state.out << markup.pre;
BOOST_FOREACH(value item, list)
{
- actions.out << "<listitem>";
- actions.out << item.get_encoded();
- actions.out << "</listitem>";
+ state.out << "<listitem>";
+ state.out << item.get_encoded();
+ state.out << "</listitem>";
}
- actions.out << markup.post;
+ state.out << markup.post;
}
- void anchor_action(quickbook::actions& actions, value anchor)
+ void anchor_action(quickbook::state& state, value anchor)
{
value_consumer values = anchor;
value anchor_id = values.consume();
// Note: anchor_id is never encoded as boostbook. If it
// is encoded, it's just things like escapes.
- add_anchor(actions, anchor_id.is_encoded() ?
+ add_anchor(state, anchor_id.is_encoded() ?
anchor_id.get_encoded() : anchor_id.get_quickbook());
values.finish();
}
void do_macro_action::operator()(std::string const& str) const
{
- write_anchors(actions, phrase);
+ write_anchors(state, phrase);
if (str == quickbook_get_date)
{
@@ -582,56 +685,69 @@ namespace quickbook
out << *first++;
}
- void source_mode_action(quickbook::actions& actions, value source_mode)
+ void source_mode_action(quickbook::state& state, value source_mode)
+ {
+ state.source_mode = source_mode_tags::name(source_mode.get_tag());
+ }
+
+ void next_source_mode_action(quickbook::state& state, value source_mode)
{
- actions.source_mode = source_mode_tags::name(source_mode.get_tag());
+ value_consumer values = source_mode;
+ state.source_mode_next = values.consume();
+ values.finish();
}
- void code_action::operator()(parse_iterator first, parse_iterator last) const
+ void code_action(quickbook::state& state, value code_block)
{
- bool inline_code = type == inline_ ||
- (type == inline_block && qbk_version_n < 106u);
- bool block = type != inline_;
+ int code_tag = code_block.get_tag();
+
+ value_consumer values = code_block;
+ string_ref code_value = values.consume().get_quickbook();
+ values.finish();
+
+ bool inline_code = code_tag == code_tags::inline_code ||
+ (code_tag == code_tags::inline_code_block && qbk_version_n < 106u);
+ bool block = code_tag != code_tags::inline_code;
+
+ std::string source_mode = state.source_mode_next.empty() ?
+ state.source_mode : state.source_mode_next.get_quickbook();
+ state.source_mode_next = value();
if (inline_code) {
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
}
else {
- actions.paragraph();
- write_anchors(actions, actions.out);
+ paragraph_action para(state);
+ para();
+ write_anchors(state, state.out);
}
- std::string str;
-
if (block) {
// preprocess the code section to remove the initial indentation
mapped_file_builder mapped;
- mapped.start(actions.current_file);
- mapped.unindent_and_add(first.base(), last.base());
+ mapped.start(state.current_file);
+ mapped.unindent_and_add(code_value.begin(), code_value.end());
file_ptr f = mapped.release();
if (f->source.empty())
return; // Nothing left to do here. The program is empty.
+ if (qbk_version_n >= 107u) state.start_callouts();
+
parse_iterator first_(f->source.begin());
parse_iterator last_(f->source.end());
file_ptr saved_file = f;
- boost::swap(actions.current_file, saved_file);
+ boost::swap(state.current_file, saved_file);
// print the code with syntax coloring
- str = syntax_highlight(first_, last_, actions, actions.source_mode);
+ std::string str = syntax_highlight(first_, last_, state,
+ source_mode, block);
- boost::swap(actions.current_file, saved_file);
- }
- else {
- parse_iterator first_(first);
- str = syntax_highlight(first_, last, actions, actions.source_mode);
- }
+ boost::swap(state.current_file, saved_file);
- if (block) {
- collector& output = inline_code ? actions.phrase : actions.out;
+ collector& output = inline_code ? state.phrase : state.out;
// We must not place a \n after the <programlisting> tag
// otherwise PDF output starts code blocks with a blank line:
@@ -639,24 +755,31 @@ namespace quickbook
output << "<programlisting>";
output << str;
output << "</programlisting>\n";
+
+ if (qbk_version_n >= 107u) output << state.end_callouts();
}
else {
- actions.phrase << "<code>";
- actions.phrase << str;
- actions.phrase << "</code>";
+ parse_iterator first_(code_value.begin());
+ parse_iterator last_(code_value.end());
+ std::string str = syntax_highlight(first_, last_, state,
+ source_mode, block);
+
+ state.phrase << "<code>";
+ state.phrase << str;
+ state.phrase << "</code>";
}
}
void plain_char_action::operator()(char ch) const
{
- write_anchors(actions, phrase);
+ write_anchors(state, phrase);
detail::print_char(ch, phrase.get());
}
void plain_char_action::operator()(parse_iterator first, parse_iterator last) const
{
- write_anchors(actions, phrase);
+ write_anchors(state, phrase);
while (first != last)
detail::print_char(*first++, phrase.get());
@@ -664,7 +787,7 @@ namespace quickbook
void escape_unicode_action::operator()(parse_iterator first, parse_iterator last) const
{
- write_anchors(actions, phrase);
+ write_anchors(state, phrase);
while(first != last && *first == '0') ++first;
@@ -701,9 +824,9 @@ namespace quickbook
}
}
- void image_action(quickbook::actions& actions, value image)
+ void image_action(quickbook::state& state, value image)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
// Note: attributes are never encoded as boostbook, if they're
// encoded, it's just things like escapes.
@@ -723,7 +846,7 @@ namespace quickbook
{
detail::outwarn(name.get_file(), name.get_position())
<< "Duplicate image attribute: "
- << detail::utf8(name.get_quickbook())
+ << name.get_quickbook()
<< std::endl;
}
}
@@ -748,10 +871,10 @@ namespace quickbook
detail::outerr(attributes["fileref"].get_file(), attributes["fileref"].get_position()) :
detail::outwarn(attributes["fileref"].get_file(), attributes["fileref"].get_position()))
<< "Image path isn't portable: '"
- << detail::utf8(fileref)
+ << fileref
<< "'"
<< std::endl;
- if (qbk_version_n >= 106u) ++actions.error_count;
+ if (qbk_version_n >= 106u) ++state.error_count;
}
boost::replace(fileref, '\\', '/');
@@ -814,10 +937,13 @@ namespace quickbook
// Now load the SVG file:
//
std::string svg_text;
- fs::ifstream fs(img);
- char c;
- while(fs.get(c) && fs.good())
- svg_text.push_back(c);
+ if (state.add_dependency(img)) {
+ fs::ifstream fs(img);
+ std::stringstream buffer;
+ buffer << fs.rdbuf();
+ svg_text = buffer.str();
+ }
+
//
// Extract the svg header from the file:
//
@@ -853,31 +979,31 @@ namespace quickbook
}
}
- actions.phrase << "<inlinemediaobject>";
+ state.phrase << "<inlinemediaobject>";
- actions.phrase << "<imageobject><imagedata";
+ state.phrase << "<imageobject><imagedata";
BOOST_FOREACH(attribute_map::value_type const& attr, attributes)
{
- actions.phrase << " " << attr.first << "=\"";
- write_plain_text(actions.phrase.get(), attr.second);
- actions.phrase << "\"";
+ state.phrase << " " << attr.first << "=\"";
+ write_plain_text(state.phrase.get(), attr.second);
+ state.phrase << "\"";
}
- actions.phrase << "></imagedata></imageobject>";
+ state.phrase << "></imagedata></imageobject>";
// Add a textobject containing the alt tag from earlier.
// This will be used for the alt tag in html.
if (alt_text.check()) {
- actions.phrase << "<textobject><phrase>";
- write_plain_text(actions.phrase.get(), alt_text);
- actions.phrase << "</phrase></textobject>";
+ state.phrase << "<textobject><phrase>";
+ write_plain_text(state.phrase.get(), alt_text);
+ state.phrase << "</phrase></textobject>";
}
- actions.phrase << "</inlinemediaobject>";
+ state.phrase << "</inlinemediaobject>";
}
- void macro_definition_action(quickbook::actions& actions, quickbook::value macro_definition)
+ void macro_definition_action(quickbook::state& state, quickbook::value macro_definition)
{
value_consumer values = macro_definition;
std::string macro_id = values.consume().get_quickbook();
@@ -887,7 +1013,7 @@ namespace quickbook
values.finish();
std::string* existing_macro =
- boost::spirit::classic::find(actions.macro, macro_id.c_str());
+ boost::spirit::classic::find(state.macro, macro_id.c_str());
quickbook::ignore_variable(&existing_macro);
if (existing_macro)
@@ -900,13 +1026,13 @@ namespace quickbook
// return;
}
- actions.macro.add(
+ state.macro.add(
macro_id.begin()
, macro_id.end()
, phrase);
}
- void template_body_action(quickbook::actions& actions, quickbook::value template_definition)
+ void template_body_action(quickbook::state& state, quickbook::value template_definition)
{
value_consumer values = template_definition;
std::string identifier = values.consume().get_quickbook();
@@ -920,16 +1046,16 @@ namespace quickbook
value body = values.consume();
BOOST_ASSERT(!values.check());
- if (!actions.templates.add(
+ if (!state.templates.add(
template_symbol(
identifier,
template_values,
body,
- &actions.templates.top_scope())))
+ &state.templates.top_scope())))
{
detail::outwarn(body.get_file(), body.get_position())
- << "Template Redefinition: " << detail::utf8(identifier) << std::endl;
- ++actions.error_count;
+ << "Template Redefinition: " << identifier << std::endl;
+ ++state.error_count;
}
}
@@ -1050,7 +1176,7 @@ namespace quickbook
, std::vector<std::string> const& params
, template_scope const& scope
, string_iterator first
- , quickbook::actions& actions
+ , quickbook::state& state
)
{
std::vector<value>::const_iterator arg = args.begin();
@@ -1060,12 +1186,12 @@ namespace quickbook
// Store each of the argument passed in as local templates:
while (arg != args.end())
{
- if (!actions.templates.add(
+ if (!state.templates.add(
template_symbol(*tpl, empty_params, *arg, &scope)))
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Duplicate Symbol Found" << std::endl;
- ++actions.error_count;
+ ++state.error_count;
return std::make_pair(false, tpl);
}
++arg; ++tpl;
@@ -1075,47 +1201,50 @@ namespace quickbook
bool parse_template(
value const& content
- , quickbook::actions& actions
+ , quickbook::state& state
)
{
- file_ptr saved_current_file = actions.current_file;
+ file_ptr saved_current_file = state.current_file;
- actions.current_file = content.get_file();
+ state.current_file = content.get_file();
string_ref source = content.get_quickbook();
parse_iterator first(source.begin());
parse_iterator last(source.end());
bool r = cl::parse(first, last,
- content.get_tag() == template_tags::block ?
- actions.grammar().block :
- actions.grammar().inline_phrase
+ content.get_tag() == template_tags::phrase ?
+ state.grammar().inline_phrase :
+ state.grammar().block
).full;
- boost::swap(actions.current_file, saved_current_file);
+ boost::swap(state.current_file, saved_current_file);
return r;
}
}
- void call_template(quickbook::actions& actions,
+ void call_template(quickbook::state& state,
template_symbol const* symbol,
std::vector<value> const& args,
string_iterator first)
{
+ bool is_block = symbol->content.get_tag() != template_tags::phrase;
+
// If this template contains already encoded text, then just
// write it out, without going through any of the rigamarole.
if (symbol->content.is_encoded())
{
- if (symbol->content.get_tag() == template_tags::block)
+ if (is_block)
{
- actions.paragraph();
- actions.out << symbol->content.get_encoded();
+ paragraph_action para(state);
+ para();
+ state.out << symbol->content.get_encoded();
}
else
{
- actions.phrase << symbol->content.get_encoded();
+ state.phrase << symbol->content.get_encoded();
}
return;
@@ -1126,36 +1255,36 @@ namespace quickbook
//
// Note that for quickbook 1.4- this value is just ignored when the
// arguments are expanded.
- template_scope const& call_scope = actions.templates.top_scope();
+ template_scope const& call_scope = state.templates.top_scope();
std::string block;
std::string phrase;
{
- template_state state(actions);
- actions.templates.start_template(symbol);
+ template_state save(state);
+ state.templates.start_template(symbol);
qbk_version_n = symbol->content.get_file()->version();
- ++actions.template_depth;
- if (actions.template_depth > actions.max_template_depth)
+ ++state.template_depth;
+ if (state.template_depth > state.max_template_depth)
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Infinite loop detected" << std::endl;
- ++actions.error_count;
+ ++state.error_count;
return;
}
// Store the current section level so that we can ensure that
// [section] and [endsect] tags in the template are balanced.
- actions.min_section_level = actions.ids.section_level();
+ state.min_section_level = state.ids.section_level();
///////////////////////////////////
// Prepare the arguments as local templates
bool get_arg_result;
std::vector<std::string>::const_iterator tpl;
boost::tie(get_arg_result, tpl) =
- get_arguments(args, symbol->params, call_scope, first, actions);
+ get_arguments(args, symbol->params, call_scope, first, state);
if (!get_arg_result)
{
@@ -1165,128 +1294,67 @@ namespace quickbook
///////////////////////////////////
// parse the template body:
- if (!parse_template(symbol->content, actions))
+ if (!parse_template(symbol->content, state))
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Expanding "
- << (symbol->content.get_tag() == template_tags::block ? "block" : "phrase")
- << " template: " << detail::utf8(symbol->identifier) << std::endl
+ << (is_block ? "block" : "phrase")
+ << " template: " << symbol->identifier << std::endl
<< std::endl
<< "------------------begin------------------" << std::endl
- << detail::utf8(symbol->content.get_quickbook())
+ << symbol->content.get_quickbook()
<< "------------------end--------------------" << std::endl
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
return;
}
- if (actions.ids.section_level() != actions.min_section_level)
+ if (state.ids.section_level() != state.min_section_level)
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Mismatched sections in template "
- << detail::utf8(symbol->identifier)
+ << symbol->identifier
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
return;
}
- actions.out.swap(block);
- actions.phrase.swap(phrase);
+ state.out.swap(block);
+ state.phrase.swap(phrase);
}
- if(symbol->content.get_tag() == template_tags::block || !block.empty()) {
- actions.paragraph(); // For paragraphs before the template call.
- actions.out << block;
- actions.phrase << phrase;
- actions.paragraph();
+ if(is_block || !block.empty()) {
+ paragraph_action para(state);
+ para(); // For paragraphs before the template call.
+ state.out << block;
+ state.phrase << phrase;
+ para();
}
else {
- actions.phrase << phrase;
+ state.phrase << phrase;
}
}
- void call_code_snippet(quickbook::actions& actions,
+ void call_code_snippet(quickbook::state& state,
template_symbol const* symbol,
string_iterator first)
{
- value_consumer values = symbol->content;
- value content = values.consume(template_tags::block);
- value callouts = values.consume();
- values.finish();
-
- std::vector<std::string> callout_ids;
+ assert(symbol->params.size() == 0);
std::vector<value> args;
- unsigned int size = symbol->params.size();
- std::string callout_base("c");
-
- for(unsigned int i = 0; i < size; ++i)
- {
- std::string callout_id1 = actions.ids.add_id(callout_base, id_category::numbered);
- std::string callout_id2 = actions.ids.add_id(callout_base, id_category::numbered);
-
- std::string code;
- code += "<co id=\"" + callout_id1 + "\" ";
- code += "linkends=\"" + callout_id2 + "\" />";
-
- args.push_back(encoded_value(code, template_tags::phrase));
- callout_ids.push_back(callout_id1);
- callout_ids.push_back(callout_id2);
- }
// Create a fake symbol for call_template
template_symbol t(
symbol->identifier,
symbol->params,
- content,
+ symbol->content,
symbol->lexical_parent);
- call_template(actions, &t, args, first);
-
- std::string block;
-
- if(!callouts.empty())
- {
- block += "<calloutlist>";
- int i = 0;
- BOOST_FOREACH(value c, callouts)
- {
- std::string callout_id1 = callout_ids[i++];
- std::string callout_id2 = callout_ids[i++];
-
- std::string callout_value;
- {
- template_state state(actions);
- ++actions.template_depth;
-
- bool r = parse_template(c, actions);
-
- if(!r)
- {
- detail::outerr(c.get_file(), c.get_position())
- << "Expanding callout." << std::endl
- << "------------------begin------------------" << std::endl
- << detail::utf8(c.get_quickbook())
- << std::endl
- << "------------------end--------------------" << std::endl
- ;
- ++actions.error_count;
- return;
- }
-
- actions.out.swap(callout_value);
- }
-
- block += "<callout arearefs=\"" + callout_id1 + "\" ";
- block += "id=\"" + callout_id2 + "\">";
- block += callout_value;
- block += "</callout>";
- }
- block += "</calloutlist>";
- }
- actions.out << block;
+ state.start_callouts();
+ call_template(state, &t, args, first);
+ state.out << state.end_callouts();
}
- void do_template_action(quickbook::actions& actions, value template_list,
+ void do_template_action(quickbook::state& state, value template_list,
string_iterator first)
{
// Get the arguments
@@ -1306,7 +1374,7 @@ namespace quickbook
values.finish();
- template_symbol const* symbol = actions.templates.find(identifier);
+ template_symbol const* symbol = state.templates.find(identifier);
BOOST_ASSERT(symbol);
// Deal with escaped templates.
@@ -1315,19 +1383,19 @@ namespace quickbook
{
if (!args.empty())
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Arguments for escaped template."
<<std::endl;
- ++actions.error_count;
+ ++state.error_count;
}
if (symbol->content.is_encoded())
{
- actions.phrase << symbol->content.get_encoded();
+ state.phrase << symbol->content.get_encoded();
}
else
{
- actions.phrase << symbol->content.get_quickbook();
+ state.phrase << symbol->content.get_quickbook();
/*
@@ -1339,7 +1407,7 @@ namespace quickbook
quickbook::detail::markup escape_markup
= detail::get_markup(phrase_tags::escape);
- actions.phrase
+ state.phrase
<< escape_markup.pre
<< symbol->content.get_quickbook()
<< escape_markup.post
@@ -1359,11 +1427,11 @@ namespace quickbook
case template_tags::phrase:
// Break the arguments for a template
- break_arguments(args, symbol->params, actions.current_file->path);
+ break_arguments(args, symbol->params, state.current_file->path);
if (args.size() != symbol->params.size())
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Invalid number of arguments passed. Expecting: "
<< symbol->params.size()
<< " argument(s), got: "
@@ -1371,26 +1439,26 @@ namespace quickbook
<< " argument(s) instead."
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
return;
}
- call_template(actions, symbol, args, first);
+ call_template(state, symbol, args, first);
break;
case template_tags::snippet:
if (!args.empty())
{
- detail::outerr(actions.current_file, first)
+ detail::outerr(state.current_file, first)
<< "Arguments for code snippet."
<<std::endl;
- ++actions.error_count;
+ ++state.error_count;
args.clear();
}
- call_code_snippet(actions, symbol, first);
+ call_code_snippet(state, symbol, first);
break;
default:
@@ -1398,9 +1466,9 @@ namespace quickbook
}
}
- void link_action(quickbook::actions& actions, value link)
+ void link_action(quickbook::state& state, value link)
{
- write_anchors(actions, actions.phrase);
+ write_anchors(state, state.phrase);
detail::markup markup = detail::get_markup(link.get_tag());
@@ -1414,57 +1482,57 @@ namespace quickbook
std::string dst = dst_value.is_encoded() ?
dst_value.get_encoded() : dst_value.get_quickbook();
- actions.phrase << markup.pre;
- detail::print_string(dst, actions.phrase.get());
- actions.phrase << "\">";
+ state.phrase << markup.pre;
+ detail::print_string(dst, state.phrase.get());
+ state.phrase << "\">";
if (content.empty())
- detail::print_string(dst, actions.phrase.get());
+ detail::print_string(dst, state.phrase.get());
else
- actions.phrase << content.get_encoded();
+ state.phrase << content.get_encoded();
- actions.phrase << markup.post;
+ state.phrase << markup.post;
}
- void variable_list_action(quickbook::actions& actions, value variable_list)
+ void variable_list_action(quickbook::state& state, value variable_list)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
value_consumer values = variable_list;
std::string title = values.consume(table_tags::title).get_quickbook();
- actions.out << "<variablelist>\n";
+ state.out << "<variablelist>\n";
- actions.out << "<title>";
- detail::print_string(title, actions.out.get());
- actions.out << "</title>\n";
+ state.out << "<title>";
+ detail::print_string(title, state.out.get());
+ state.out << "</title>\n";
BOOST_FOREACH(value_consumer entry, values) {
- actions.out << "<varlistentry>";
+ state.out << "<varlistentry>";
if(entry.check()) {
- actions.out << "<term>";
- actions.out << entry.consume().get_encoded();
- actions.out << "</term>";
+ state.out << "<term>";
+ state.out << entry.consume().get_encoded();
+ state.out << "</term>";
}
if(entry.check()) {
- actions.out << "<listitem>";
- BOOST_FOREACH(value phrase, entry) actions.out << phrase.get_encoded();
- actions.out << "</listitem>";
+ state.out << "<listitem>";
+ BOOST_FOREACH(value phrase, entry) state.out << phrase.get_encoded();
+ state.out << "</listitem>";
}
- actions.out << "</varlistentry>\n";
+ state.out << "</varlistentry>\n";
}
- actions.out << "</variablelist>\n";
+ state.out << "</variablelist>\n";
values.finish();
}
- void table_action(quickbook::actions& actions, value table)
+ void table_action(quickbook::state& state, value table)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
value_consumer values = table;
@@ -1478,14 +1546,14 @@ namespace quickbook
std::string table_id;
if (!element_id.empty()) {
- table_id = actions.ids.add_id(element_id, id_category::explicit_id);
+ table_id = state.ids.add_id(element_id, id_category::explicit_id);
}
else if (has_title) {
- if (actions.ids.compatibility_version() >= 105) {
- table_id = actions.ids.add_id(detail::make_identifier(title.get_quickbook()), id_category::generated);
+ if (state.ids.compatibility_version() >= 105) {
+ table_id = state.ids.add_id(detail::make_identifier(title.get_quickbook()), id_category::generated);
}
else {
- table_id = actions.ids.add_id("t", id_category::numbered);
+ table_id = state.ids.add_id("t", id_category::numbered);
}
}
@@ -1503,64 +1571,64 @@ namespace quickbook
if (has_title)
{
- actions.out << "<table frame=\"all\"";
+ state.out << "<table frame=\"all\"";
if(!table_id.empty())
- actions.out << " id=\"" << table_id << "\"";
- actions.out << ">\n";
- actions.out << "<title>";
+ state.out << " id=\"" << table_id << "\"";
+ state.out << ">\n";
+ state.out << "<title>";
if (qbk_version_n < 106u) {
- detail::print_string(title.get_quickbook(), actions.out.get());
+ detail::print_string(title.get_quickbook(), state.out.get());
}
else {
- actions.out << title.get_encoded();
+ state.out << title.get_encoded();
}
- actions.out << "</title>";
+ state.out << "</title>";
}
else
{
- actions.out << "<informaltable frame=\"all\"";
+ state.out << "<informaltable frame=\"all\"";
if(!table_id.empty())
- actions.out << " id=\"" << table_id << "\"";
- actions.out << ">\n";
+ state.out << " id=\"" << table_id << "\"";
+ state.out << ">\n";
}
- actions.out << "<tgroup cols=\"" << span_count << "\">\n";
+ state.out << "<tgroup cols=\"" << span_count << "\">\n";
if (row_count > 1)
{
- actions.out << "<thead>" << "<row>";
+ state.out << "<thead>" << "<row>";
BOOST_FOREACH(value cell, values.consume()) {
- actions.out << "<entry>" << cell.get_encoded() << "</entry>";
+ state.out << "<entry>" << cell.get_encoded() << "</entry>";
}
- actions.out << "</row>\n" << "</thead>\n";
+ state.out << "</row>\n" << "</thead>\n";
}
- actions.out << "<tbody>\n";
+ state.out << "<tbody>\n";
BOOST_FOREACH(value row, values) {
- actions.out << "<row>";
+ state.out << "<row>";
BOOST_FOREACH(value cell, row) {
- actions.out << "<entry>" << cell.get_encoded() << "</entry>";
+ state.out << "<entry>" << cell.get_encoded() << "</entry>";
}
- actions.out << "</row>\n";
+ state.out << "</row>\n";
}
values.finish();
- actions.out << "</tbody>\n"
- << "</tgroup>\n";
+ state.out << "</tbody>\n"
+ << "</tgroup>\n";
if (has_title)
{
- actions.out << "</table>\n";
+ state.out << "</table>\n";
}
else
{
- actions.out << "</informaltable>\n";
+ state.out << "</informaltable>\n";
}
}
- void begin_section_action(quickbook::actions& actions, value begin_section_list)
+ void begin_section_action(quickbook::state& state, value begin_section_list)
{
value_consumer values = begin_section_list;
@@ -1568,7 +1636,7 @@ namespace quickbook
value content = values.consume();
values.finish();
- std::string full_id = actions.ids.begin_section(
+ std::string full_id = state.ids.begin_section(
!element_id.empty() ?
element_id.get_quickbook() :
detail::make_identifier(content.get_quickbook()),
@@ -1576,48 +1644,48 @@ namespace quickbook
id_category::explicit_section_id :
id_category::generated_section);
- actions.out << "\n<section id=\"" << full_id << "\">\n";
- actions.out << "<title>";
+ state.out << "\n<section id=\"" << full_id << "\">\n";
+ state.out << "<title>";
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
- if (self_linked_headers && actions.ids.compatibility_version() >= 103)
+ if (self_linked_headers && state.ids.compatibility_version() >= 103)
{
- actions.out << "<link linkend=\"" << full_id << "\">"
+ state.out << "<link linkend=\"" << full_id << "\">"
<< content.get_encoded()
<< "</link>"
;
}
else
{
- actions.out << content.get_encoded();
+ state.out << content.get_encoded();
}
- actions.out << "</title>\n";
+ state.out << "</title>\n";
}
- void end_section_action(quickbook::actions& actions, value end_section, string_iterator first)
+ void end_section_action(quickbook::state& state, value end_section, string_iterator first)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
- if (actions.ids.section_level() <= actions.min_section_level)
+ if (state.ids.section_level() <= state.min_section_level)
{
- file_position const pos = actions.current_file->position_of(first);
+ file_position const pos = state.current_file->position_of(first);
- detail::outerr(actions.current_file->path, pos.line)
+ detail::outerr(state.current_file->path, pos.line)
<< "Mismatched [endsect] near column " << pos.column << ".\n";
- ++actions.error_count;
+ ++state.error_count;
return;
}
- actions.out << "</section>";
- actions.ids.end_section();
+ state.out << "</section>";
+ state.ids.end_section();
}
void element_id_warning_action::operator()(parse_iterator first, parse_iterator) const
{
- detail::outwarn(actions.current_file, first.base()) << "Empty id.\n";
+ detail::outwarn(state.current_file, first.base()) << "Empty id.\n";
}
// Not a general purpose normalization function, just
@@ -1695,57 +1763,84 @@ namespace quickbook
return result;
}
- fs::path check_path(value const& path, quickbook::actions& actions)
+ struct path_details {
+ // Will possibly add 'url' and 'glob' to this list later:
+ enum path_type { path };
+
+ std::string value;
+ path_type type;
+
+ path_details(std::string const& value, path_type type) :
+ value(value), type(type)
+ {
+ }
+ };
+
+ path_details check_path(value const& path, quickbook::state& state)
{
- std::string path_text = path.is_encoded() ? path.get_encoded() :
- path.get_quickbook();
+ // Paths are encoded for quickbook 1.6+ and also xmlbase
+ // values (technically xmlbase is a 1.6 feature, but that
+ // isn't enforced as it's backwards compatible).
+ //
+ // Counter-intuitively: encoded == plain text here.
+
+ std::string path_text = qbk_version_n >= 106u || path.is_encoded() ?
+ path.get_encoded() : path.get_quickbook();
if(path_text.find('\\') != std::string::npos)
{
- (qbk_version_n >= 106u ?
- detail::outerr(path.get_file(), path.get_position()) :
- detail::outwarn(path.get_file(), path.get_position()))
- << "Path isn't portable: '"
- << detail::utf8(path_text)
+ quickbook::detail::ostream* err;
+
+ if (qbk_version_n >= 106u) {
+ err = &detail::outerr(path.get_file(), path.get_position());
+ ++state.error_count;
+ }
+ else {
+ err = &detail::outwarn(path.get_file(), path.get_position());
+ }
+
+ *err << "Path isn't portable: '"
+ << path_text
<< "'"
<< std::endl;
- if (qbk_version_n >= 106u) ++actions.error_count;
+
+ boost::replace(path_text, '\\', '/');
}
-
- boost::replace(path_text, '\\', '/');
-
- return detail::generic_to_path(path_text);
+
+ return path_details(path_text, path_details::path);
}
- xinclude_path calculate_xinclude_path(value const& p, quickbook::actions& actions)
+ xinclude_path calculate_xinclude_path(value const& p, quickbook::state& state)
{
- fs::path path = check_path(p, actions);
+ path_details details = check_path(p, state);
+
+ fs::path path = detail::generic_to_path(details.value);
fs::path full_path = path;
// If the path is relative
if (!path.has_root_directory())
{
// Resolve the path from the current file
- full_path = actions.current_file->path.parent_path() / path;
+ full_path = state.current_file->path.parent_path() / path;
// Then calculate relative to the current xinclude_base.
- path = path_difference(actions.xinclude_base, full_path);
+ path = path_difference(state.xinclude_base, full_path);
}
return xinclude_path(full_path, detail::escape_uri(detail::path_to_generic(path)));
}
- void xinclude_action(quickbook::actions& actions, value xinclude)
+ void xinclude_action(quickbook::state& state, value xinclude)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
value_consumer values = xinclude;
- xinclude_path x = calculate_xinclude_path(values.consume(), actions);
+ xinclude_path x = calculate_xinclude_path(values.consume(), state);
values.finish();
- actions.out << "\n<xi:include href=\"";
- detail::print_string(x.uri, actions.out.get());
- actions.out << "\" />\n";
+ state.out << "\n<xi:include href=\"";
+ detail::print_string(x.uri, state.out.get());
+ state.out << "\" />\n";
}
namespace
@@ -1757,41 +1852,67 @@ namespace quickbook
fs::path filename;
fs::path filename_relative;
+
+ bool operator < (include_search_return const & other) const
+ {
+ if (filename_relative < other.filename_relative) return true;
+ else if (other.filename_relative < filename_relative) return false;
+ else return filename < other.filename;
+ }
};
- include_search_return include_search(fs::path const& path,
- quickbook::actions const& actions)
+ std::set<include_search_return> include_search(path_details const& details,
+ quickbook::state& state, string_iterator pos)
{
- fs::path current = actions.current_file->path.parent_path();
+ std::set<include_search_return> result;
+
+ fs::path path = detail::generic_to_path(details.value);
// If the path is relative, try and resolve it.
if (!path.has_root_directory() && !path.has_root_name())
{
+ fs::path local_path =
+ state.current_file->path.parent_path() / path;
+
// See if it can be found locally first.
- if (fs::exists(current / path))
+ if (state.add_dependency(local_path))
{
- return include_search_return(
- current / path,
- actions.filename_relative.parent_path() / path);
+ result.insert(include_search_return(
+ local_path,
+ state.filename_relative.parent_path() / path));
+ return result;
}
- // Search in each of the include path locations.
BOOST_FOREACH(fs::path full, include_path)
{
full /= path;
- if (fs::exists(full))
+
+ if (state.add_dependency(full))
{
- return include_search_return(full, path);
+ result.insert(include_search_return(full, path));
+ return result;
}
}
}
+ else
+ {
+ if (state.add_dependency(path)) {
+ result.insert(include_search_return(path, path));
+ return result;
+ }
+ }
+
+ detail::outerr(state.current_file, pos)
+ << "Unable to find file: "
+ << details.value
+ << std::endl;
+ ++state.error_count;
- return include_search_return(path,
- actions.filename_relative.parent_path() / path);
+ return result;
}
}
- void load_quickbook(quickbook::actions& actions,
+ void load_quickbook(quickbook::state& state,
include_search_return const& paths,
value::tag_type load_type,
value const& include_doc_id = value())
@@ -1810,32 +1931,32 @@ namespace quickbook
//
// For old versions of quickbook, templates aren't scoped by the
// file.
- file_state state(actions,
+ file_state save(state,
load_type == block_tags::import ? file_state::scope_output :
qbk_version_n >= 106u ? file_state::scope_callables :
file_state::scope_macros);
- actions.current_file = load(paths.filename); // Throws load_error
- actions.filename_relative = paths.filename_relative;
- actions.imported = (load_type == block_tags::import);
+ state.current_file = load(paths.filename); // Throws load_error
+ state.filename_relative = paths.filename_relative;
+ state.imported = (load_type == block_tags::import);
// update the __FILENAME__ macro
- *boost::spirit::classic::find(actions.macro, "__FILENAME__")
- = detail::path_to_generic(actions.filename_relative);
+ *boost::spirit::classic::find(state.macro, "__FILENAME__")
+ = detail::path_to_generic(state.filename_relative);
// parse the file
- quickbook::parse_file(actions, include_doc_id, true);
+ quickbook::parse_file(state, include_doc_id, true);
// Don't restore source_mode on older versions.
- if (keep_inner_source_mode) state.source_mode = actions.source_mode;
+ if (keep_inner_source_mode) save.source_mode = state.source_mode;
}
// restore the __FILENAME__ macro
- *boost::spirit::classic::find(actions.macro, "__FILENAME__")
- = detail::path_to_generic(actions.filename_relative);
+ *boost::spirit::classic::find(state.macro, "__FILENAME__")
+ = detail::path_to_generic(state.filename_relative);
}
- void load_source_file(quickbook::actions& actions,
+ void load_source_file(quickbook::state& state,
include_search_return const& paths,
value::tag_type load_type,
string_iterator first,
@@ -1847,12 +1968,12 @@ namespace quickbook
std::string ext = paths.filename.extension().generic_string();
std::vector<template_symbol> storage;
// Throws load_error
- actions.error_count +=
+ state.error_count +=
load_snippets(paths.filename, storage, ext, load_type);
if (load_type == block_tags::include)
{
- actions.templates.push();
+ state.templates.push();
}
BOOST_FOREACH(template_symbol& ts, storage)
@@ -1860,12 +1981,12 @@ namespace quickbook
std::string tname = ts.identifier;
if (tname != "!")
{
- ts.lexical_parent = &actions.templates.top_scope();
- if (!actions.templates.add(ts))
+ ts.lexical_parent = &state.templates.top_scope();
+ if (!state.templates.add(ts))
{
detail::outerr(ts.content.get_file(), ts.content.get_position())
- << "Template Redefinition: " << detail::utf8(tname) << std::endl;
- ++actions.error_count;
+ << "Template Redefinition: " << tname << std::endl;
+ ++state.error_count;
}
}
}
@@ -1878,71 +1999,77 @@ namespace quickbook
if (tname == "!")
{
- ts.lexical_parent = &actions.templates.top_scope();
- call_code_snippet(actions, &ts, first);
+ ts.lexical_parent = &state.templates.top_scope();
+ call_code_snippet(state, &ts, first);
}
}
- actions.templates.pop();
+ state.templates.pop();
}
}
- void include_action(quickbook::actions& actions, value include, string_iterator first)
+ void include_action(quickbook::state& state, value include, string_iterator first)
{
- write_anchors(actions, actions.out);
+ write_anchors(state, state.out);
value_consumer values = include;
value include_doc_id = values.optional_consume(general_tags::include_id);
- include_search_return paths = include_search(
- check_path(values.consume(), actions), actions);
+ path_details details = check_path(values.consume(), state);
values.finish();
- try {
- if (qbk_version_n >= 106)
- {
- if (actions.imported && include.get_tag() == block_tags::include)
- return;
-
- std::string ext = paths.filename.extension().generic_string();
-
- if (ext == ".qbk" || ext == ".quickbook")
+ std::set<include_search_return> search = include_search(details, state, first);
+ std::set<include_search_return>::iterator i = search.begin();
+ std::set<include_search_return>::iterator e = search.end();
+ for (; i != e; ++i)
+ {
+ include_search_return const & paths = *i;
+ try {
+ if (qbk_version_n >= 106)
{
- load_quickbook(actions, paths, include.get_tag(), include_doc_id);
+ if (state.imported && include.get_tag() == block_tags::include)
+ return;
+
+ std::string ext = paths.filename.extension().generic_string();
+
+ if (ext == ".qbk" || ext == ".quickbook")
+ {
+ load_quickbook(state, paths, include.get_tag(), include_doc_id);
+ }
+ else
+ {
+ load_source_file(state, paths, include.get_tag(), first, include_doc_id);
+ }
}
else
{
- load_source_file(actions, paths, include.get_tag(), first, include_doc_id);
+ if (include.get_tag() == block_tags::include)
+ {
+ load_quickbook(state, paths, include.get_tag(), include_doc_id);
+ }
+ else
+ {
+ load_source_file(state, paths, include.get_tag(), first, include_doc_id);
+ }
}
}
- else
- {
- if (include.get_tag() == block_tags::include)
- {
- load_quickbook(actions, paths, include.get_tag(), include_doc_id);
- }
- else
- {
- load_source_file(actions, paths, include.get_tag(), first, include_doc_id);
- }
+ catch (load_error& e) {
+ ++state.error_count;
+
+ detail::outerr(state.current_file, first)
+ << "Loading file "
+ << paths.filename
+ << ": "
+ << e.what()
+ << std::endl;
}
}
- catch (load_error& e) {
- ++actions.error_count;
-
- detail::outerr(actions.current_file, first)
- << "Loading file "
- << paths.filename
- << ": "
- << detail::utf8(e.what())
- << std::endl;
- }
}
bool to_value_scoped_action::start(value::tag_type t)
{
- actions.out.push();
- actions.phrase.push();
- actions.anchors.swap(saved_anchors);
+ state.out.push();
+ state.phrase.push();
+ state.anchors.swap(saved_anchors);
tag = t;
return true;
@@ -1952,27 +2079,28 @@ namespace quickbook
{
std::string value;
- if (!actions.out.str().empty())
+ if (!state.out.str().empty())
{
- actions.paragraph();
- write_anchors(actions, actions.out);
- actions.out.swap(value);
+ paragraph_action para(state);
+ para(); // For paragraphs before the template call.
+ write_anchors(state, state.out);
+ state.out.swap(value);
}
else
{
- write_anchors(actions, actions.phrase);
- actions.phrase.swap(value);
+ write_anchors(state, state.phrase);
+ state.phrase.swap(value);
}
- actions.values.builder.insert(encoded_qbk_value(
- actions.current_file, first.base(), last.base(), value, tag));
+ state.values.builder.insert(encoded_qbk_value(
+ state.current_file, first.base(), last.base(), value, tag));
}
void to_value_scoped_action::cleanup()
{
- actions.phrase.pop();
- actions.out.pop();
- actions.anchors.swap(saved_anchors);
+ state.phrase.pop();
+ state.out.pop();
+ state.anchors.swap(saved_anchors);
}
}
diff --git a/tools/quickbook/src/actions.hpp b/tools/quickbook/src/actions.hpp
index 4f67aec09b..5a93cf949a 100644
--- a/tools/quickbook/src/actions.hpp
+++ b/tools/quickbook/src/actions.hpp
@@ -13,46 +13,33 @@
#include <string>
#include <vector>
#include "fwd.hpp"
-#include "template_stack.hpp"
#include "utils.hpp"
#include "values.hpp"
#include "scoped.hpp"
-#include "symbols.hpp"
#include <boost/spirit/include/classic_parser.hpp>
namespace quickbook
{
namespace cl = boost::spirit::classic;
- extern unsigned qbk_version_n; // qbk_major_version * 100 + qbk_minor_version
-
struct quickbook_range : cl::parser<quickbook_range> {
- quickbook_range(unsigned min_, unsigned max_)
- : min_(min_), max_(max_) {}
+ quickbook_range(unsigned lower, unsigned upper)
+ : lower(lower), upper(upper) {}
+
+ bool in_range() const;
template <typename ScannerT>
typename cl::parser_result<quickbook_range, ScannerT>::type
parse(ScannerT const& scan) const
{
- if (qbk_version_n >= min_ && qbk_version_n < max_)
- {
- return scan.empty_match();
- }
- else
- {
- return scan.no_match();
- }
+ return in_range() ? scan.empty_match() : scan.no_match();
}
- unsigned min_, max_;
+ unsigned lower, upper;
};
- inline quickbook_range qbk_since(unsigned min_) {
- return quickbook_range(min_, 999);
- }
-
- inline quickbook_range qbk_before(unsigned max_) {
- return quickbook_range(0, max_);
+ inline quickbook_range qbk_ver(unsigned lower, unsigned upper = 999u) {
+ return quickbook_range(lower, upper);
}
// Throws load_error
@@ -61,31 +48,32 @@ namespace quickbook
std::string syntax_highlight(
parse_iterator first, parse_iterator last,
- actions& escape_actions,
- std::string const& source_mode);
+ quickbook::state& state,
+ std::string const& source_mode,
+ bool is_block);
struct xinclude_path {
- xinclude_path(fs::path& path, std::string const& uri) :
+ xinclude_path(fs::path const& path, std::string const& uri) :
path(path), uri(uri) {}
fs::path path;
std::string uri;
};
- xinclude_path calculate_xinclude_path(value const&, quickbook::actions&);
+ xinclude_path calculate_xinclude_path(value const&, quickbook::state&);
struct error_message_action
{
// Prints an error message to std::cerr
- error_message_action(quickbook::actions& actions, std::string const& m)
- : actions(actions)
+ error_message_action(quickbook::state& state, std::string const& m)
+ : state(state)
, message(m)
{}
void operator()(parse_iterator, parse_iterator) const;
- quickbook::actions& actions;
+ quickbook::state& state;
std::string message;
};
@@ -93,27 +81,27 @@ namespace quickbook
{
// Prints an error message to std::cerr
- error_action(quickbook::actions& actions)
- : actions(actions) {}
+ error_action(quickbook::state& state)
+ : state(state) {}
void operator()(parse_iterator first, parse_iterator last) const;
error_message_action operator()(std::string const& message)
{
- return error_message_action(actions, message);
+ return error_message_action(state, message);
}
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct element_action
{
- element_action(quickbook::actions& actions)
- : actions(actions) {}
+ element_action(quickbook::state& state)
+ : state(state) {}
void operator()(parse_iterator, parse_iterator) const;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct paragraph_action
@@ -122,13 +110,13 @@ namespace quickbook
// doesn't output the paragraph if it's only whitespace.
paragraph_action(
- quickbook::actions& actions)
- : actions(actions) {}
+ quickbook::state& state)
+ : state(state) {}
void operator()() const;
void operator()(parse_iterator, parse_iterator) const { (*this)(); }
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct list_item_action
@@ -137,24 +125,24 @@ namespace quickbook
// doesn't output the paragraph if it's only whitespace.
list_item_action(
- quickbook::actions& actions)
- : actions(actions) {}
+ quickbook::state& state)
+ : state(state) {}
void operator()() const;
void operator()(parse_iterator, parse_iterator) const { (*this)(); }
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct phrase_end_action
{
- phrase_end_action(quickbook::actions& actions) :
- actions(actions) {}
+ phrase_end_action(quickbook::state& state) :
+ state(state) {}
void operator()() const;
void operator()(parse_iterator, parse_iterator) const { (*this)(); }
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct simple_phrase_action
@@ -163,43 +151,40 @@ namespace quickbook
simple_phrase_action(
collector& out
- , quickbook::actions& actions)
+ , quickbook::state& state)
: out(out)
- , actions(actions) {}
+ , state(state) {}
void operator()(char) const;
collector& out;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct cond_phrase_push : scoped_action_base
{
- cond_phrase_push(quickbook::actions& x)
- : actions(x) {}
+ cond_phrase_push(quickbook::state& x)
+ : state(x) {}
bool start();
void cleanup();
- quickbook::actions& actions;
+ quickbook::state& state;
bool saved_conditional;
std::vector<std::string> anchors;
};
- extern char const* quickbook_get_date;
- extern char const* quickbook_get_time;
-
struct do_macro_action
{
// Handles macro substitutions
- do_macro_action(collector& phrase, quickbook::actions& actions)
+ do_macro_action(collector& phrase, quickbook::state& state)
: phrase(phrase)
- , actions(actions) {}
+ , state(state) {}
void operator()(std::string const& str) const;
collector& phrase;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct raw_char_action
@@ -220,83 +205,63 @@ namespace quickbook
// Prints a single plain char.
// Converts '<' to "&lt;"... etc See utils.hpp
- plain_char_action(collector& phrase, quickbook::actions& actions)
+ plain_char_action(collector& phrase, quickbook::state& state)
: phrase(phrase)
- , actions(actions) {}
+ , state(state) {}
void operator()(char ch) const;
void operator()(parse_iterator first, parse_iterator last) const;
collector& phrase;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct escape_unicode_action
{
- escape_unicode_action(collector& phrase, quickbook::actions& actions)
+ escape_unicode_action(collector& phrase, quickbook::state& state)
: phrase(phrase)
- , actions(actions) {}
+ , state(state) {}
void operator()(parse_iterator first, parse_iterator last) const;
collector& phrase;
- quickbook::actions& actions;
- };
-
- struct code_action
- {
- enum code_type { block, inline_block, inline_ };
-
- // Does the actual syntax highlighing of code
-
- code_action(
- code_type type
- , quickbook::actions& actions)
- : type(type)
- , actions(actions)
- {
- }
-
- void operator()(parse_iterator first, parse_iterator last) const;
-
- code_type type;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct break_action
{
- break_action(collector& phrase, quickbook::actions& actions)
- : phrase(phrase), actions(actions) {}
+ break_action(collector& phrase, quickbook::state& state)
+ : phrase(phrase), state(state) {}
void operator()(parse_iterator f, parse_iterator) const;
collector& phrase;
- quickbook::actions& actions;
+ quickbook::state& state;
};
struct element_id_warning_action
{
- element_id_warning_action(quickbook::actions& actions_)
- : actions(actions_) {}
+ element_id_warning_action(quickbook::state& state_)
+ : state(state_) {}
void operator()(parse_iterator first, parse_iterator last) const;
- quickbook::actions& actions;
+ quickbook::state& state;
};
// Returns the doc_type, or an empty string if there isn't one.
- std::string pre(quickbook::actions& actions, parse_iterator pos, value include_doc_id, bool nested_file);
- void post(quickbook::actions& actions, std::string const& doc_type);
+ std::string pre(quickbook::state& state, parse_iterator pos, value include_doc_id, bool nested_file);
+ void post(quickbook::state& state, std::string const& doc_type);
struct to_value_scoped_action : scoped_action_base
{
- to_value_scoped_action(quickbook::actions& actions)
- : actions(actions) {}
+ to_value_scoped_action(quickbook::state& state)
+ : state(state) {}
bool start(value::tag_type = value::default_tag);
void success(parse_iterator, parse_iterator);
void cleanup();
- quickbook::actions& actions;
+ quickbook::state& state;
std::vector<std::string> saved_anchors;
value::tag_type tag;
};
diff --git a/tools/quickbook/src/actions_class.cpp b/tools/quickbook/src/actions_class.cpp
deleted file mode 100644
index d94706c91a..0000000000
--- a/tools/quickbook/src/actions_class.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*=============================================================================
- Copyright (c) 2002 2004 2006 Joel de Guzman
- Copyright (c) 2004 Eric Niebler
- Copyright (c) 2005 Thomas Guest
- http://spirit.sourceforge.net/
-
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
-=============================================================================*/
-#include "actions_class.hpp"
-#include "actions_state.hpp"
-#include "quickbook.hpp"
-#include "grammar.hpp"
-#include "input_path.hpp"
-
-#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
-#pragma warning(disable:4355)
-#endif
-
-namespace quickbook
-{
- actions::actions(fs::path const& filein_, fs::path const& xinclude_base_,
- string_stream& out_, id_manager& ids)
- : grammar_()
-
- , xinclude_base(xinclude_base_)
-
- , templates()
- , error_count(0)
- , anchors()
- , warned_about_breaks(false)
- , conditional(true)
- , ids(ids)
-
- , imported(false)
- , macro()
- , source_mode("c++")
- , current_file(0)
- , filename_relative(filein_.filename())
-
- , template_depth(0)
- , min_section_level(1)
-
- , out(out_)
- , phrase()
- , values(&current_file)
-
- , to_value(*this)
- , scoped_cond_phrase(*this)
-
- , element(*this)
- , error(*this)
- , code(code_action::block, *this)
- , code_block(code_action::inline_block, *this)
- , inline_code(code_action::inline_, *this)
- , paragraph(*this)
- , list_item(*this)
- , phrase_end(*this)
- , raw_char(phrase)
- , plain_char(phrase, *this)
- , escape_unicode(phrase, *this)
-
- , simple_markup(phrase, *this)
-
- , break_(phrase, *this)
- , do_macro(phrase, *this)
-
- , element_id_warning(*this)
- {
- // add the predefined macros
- macro.add
- ("__DATE__", std::string(quickbook_get_date))
- ("__TIME__", std::string(quickbook_get_time))
- ("__FILENAME__", detail::path_to_generic(filename_relative))
- ;
-
- boost::scoped_ptr<quickbook_grammar> g(
- new quickbook_grammar(*this));
- grammar_.swap(g);
- }
-
- quickbook_grammar& actions::grammar() const {
- return *grammar_;
- }
-
- file_state::file_state(actions& a, scope_flags scope)
- : a(a)
- , scope(scope)
- , qbk_version(qbk_version_n)
- , imported(a.imported)
- , current_file(a.current_file)
- , filename_relative(a.filename_relative)
- , xinclude_base(a.xinclude_base)
- , source_mode(a.source_mode)
- , macro()
- {
- if (scope & scope_macros) macro = a.macro;
- if (scope & scope_templates) a.templates.push();
- if (scope & scope_output) {
- a.out.push();
- a.phrase.push();
- }
- a.values.builder.save();
- }
-
- file_state::~file_state()
- {
- a.values.builder.restore();
- boost::swap(qbk_version_n, qbk_version);
- boost::swap(a.imported, imported);
- boost::swap(a.current_file, current_file);
- boost::swap(a.filename_relative, filename_relative);
- boost::swap(a.xinclude_base, xinclude_base);
- boost::swap(a.source_mode, source_mode);
- if (scope & scope_output) {
- a.out.pop();
- a.phrase.pop();
- }
- if (scope & scope_templates) a.templates.pop();
- if (scope & scope_macros) a.macro = macro;
- }
-
- template_state::template_state(actions& a)
- : file_state(a, file_state::scope_all)
- , template_depth(a.template_depth)
- , min_section_level(a.min_section_level)
- {
- }
-
- template_state::~template_state()
- {
- boost::swap(a.template_depth, template_depth);
- boost::swap(a.min_section_level, min_section_level);
- }
-}
diff --git a/tools/quickbook/src/block_element_grammar.cpp b/tools/quickbook/src/block_element_grammar.cpp
index f188e1379f..1f5d5daec4 100644
--- a/tools/quickbook/src/block_element_grammar.cpp
+++ b/tools/quickbook/src/block_element_grammar.cpp
@@ -9,7 +9,8 @@
=============================================================================*/
#include "utils.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "grammar_impl.hpp"
#include "block_tags.hpp"
#include "template_tags.hpp"
@@ -43,20 +44,26 @@ namespace quickbook
block_element_grammar_local& local = cleanup_.add(
new block_element_grammar_local);
+ // Actions
+ error_action error(state);
+ element_id_warning_action element_id_warning(state);
+ raw_char_action raw_char(state.phrase);
+ scoped_parser<to_value_scoped_action> to_value(state);
+
local.element_id =
!( ':'
- >> ( !(qbk_since(105u) >> space)
- >> (+(cl::alnum_p | '_')) [actions.values.entry(ph::arg1, ph::arg2, general_tags::element_id)]
- | cl::eps_p [actions.element_id_warning]
+ >> ( !(qbk_ver(105u) >> space)
+ >> (+(cl::alnum_p | '_')) [state.values.entry(ph::arg1, ph::arg2, general_tags::element_id)]
+ | cl::eps_p [element_id_warning]
)
)
;
local.element_id_1_5 =
- !(qbk_since(105u) >> local.element_id);
+ !(qbk_ver(105u) >> local.element_id);
local.element_id_1_6 =
- !(qbk_since(106u) >> local.element_id);
+ !(qbk_ver(106u) >> local.element_id);
elements.add
("section", element_info(element_info::block, &local.begin_section, block_tags::begin_section))
@@ -110,10 +117,10 @@ namespace quickbook
;
local.preformatted =
- ( qbk_before(106) >> space
- | qbk_since(106) >> blank >> !eol
+ ( qbk_ver(0, 106) >> space
+ | qbk_ver(106) >> blank >> !eol
)
- >> actions.to_value()
+ >> to_value()
[
inside_preformatted
]
@@ -125,7 +132,7 @@ namespace quickbook
local.def_macro =
space
- >> macro_identifier [actions.values.entry(ph::arg1, ph::arg2)]
+ >> macro_identifier [state.values.entry(ph::arg1, ph::arg2)]
>> blank
>> local.inner_phrase
;
@@ -144,20 +151,20 @@ namespace quickbook
local.template_ =
space
- >> local.template_id [actions.values.entry(ph::arg1, ph::arg2)]
- >> actions.values.list()[
+ >> local.template_id [state.values.entry(ph::arg1, ph::arg2)]
+ >> state.values.list()[
!(
space >> '['
>> *(
space
- >> local.template_id [actions.values.entry(ph::arg1, ph::arg2)]
+ >> local.template_id [state.values.entry(ph::arg1, ph::arg2)]
)
>> space >> ']'
)
]
>> ( cl::eps_p(*cl::blank_p >> cl::eol_p)
- >> local.template_body [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)]
- | local.template_body [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
+ >> local.template_body [state.values.entry(ph::arg1, ph::arg2, template_tags::block)]
+ | local.template_body [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
)
;
@@ -180,17 +187,17 @@ namespace quickbook
local.varlistentry =
space
>> cl::ch_p('[')
- >> actions.values.list()
+ >> state.values.list()
[
(
local.varlistterm
>> ( +local.cell
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
)
>> cl::ch_p(']')
>> space
)
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
]
;
@@ -200,7 +207,7 @@ namespace quickbook
>> local.inner_phrase
>> ( cl::ch_p(']')
>> space
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
)
;
@@ -224,22 +231,22 @@ namespace quickbook
>>
(
(
- actions.values.list(table_tags::row)
+ state.values.list(table_tags::row)
[ *local.cell
]
>> cl::ch_p(']')
>> space
)
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
)
;
local.table_title =
- qbk_before(106)
- >> (*(cl::anychar_p - eol)) [actions.values.entry(ph::arg1, ph::arg2, table_tags::title)]
+ qbk_ver(0, 106)
+ >> (*(cl::anychar_p - eol)) [state.values.entry(ph::arg1, ph::arg2, table_tags::title)]
>> (+eol)
- | qbk_since(106)
- >> actions.to_value(table_tags::title)
+ | qbk_ver(106)
+ >> to_value(table_tags::title)
[
table_title_phrase
]
@@ -259,7 +266,7 @@ namespace quickbook
>> ( local.inner_block
>> cl::ch_p(']')
>> space
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
)
;
@@ -285,33 +292,33 @@ namespace quickbook
!(
':'
>> (*((cl::alnum_p | '_') - cl::space_p))
- [actions.values.entry(ph::arg1, ph::arg2, general_tags::include_id)]
+ [state.values.entry(ph::arg1, ph::arg2, general_tags::include_id)]
>> space
)
>> local.include_filename
;
local.include_filename =
- qbk_before(106u)
- >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)]
- | qbk_since(106u)
- >> actions.to_value()
+ qbk_ver(0, 106u)
+ >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)]
+ | qbk_ver(106u)
+ >> to_value()
[ *( raw_escape
| (cl::anychar_p - phrase_end)
- [actions.raw_char]
+ [raw_char]
)
]
;
local.inner_block =
- actions.to_value()
+ to_value()
[
inside_paragraph
]
;
local.inner_phrase =
- actions.to_value()
+ to_value()
[
paragraph_phrase
]
diff --git a/tools/quickbook/src/code_snippet.cpp b/tools/quickbook/src/code_snippet.cpp
index 8d9484cce2..4c63a3ba0e 100644
--- a/tools/quickbook/src/code_snippet.cpp
+++ b/tools/quickbook/src/code_snippet.cpp
@@ -16,6 +16,7 @@
#include "block_tags.hpp"
#include "template_stack.hpp"
#include "actions.hpp"
+#include "state.hpp"
#include "values.hpp"
#include "files.hpp"
#include "input_path.hpp"
@@ -31,13 +32,13 @@ namespace quickbook
char const* source_type)
: last_code_pos(source_file->source.begin())
, in_code(false)
- , callout_id(0)
, snippet_stack()
, storage(storage)
, source_file(source_file)
, source_type(source_type)
, error_count(0)
{
+ source_file->is_code_snippets = true;
content.start(source_file);
}
@@ -48,7 +49,6 @@ namespace quickbook
void start_snippet_impl(std::string const&, string_iterator);
void end_snippet(string_iterator first, string_iterator last);
void end_snippet_impl(string_iterator);
- void callout(string_iterator first, string_iterator last);
void end_file(string_iterator, string_iterator);
void append_code(string_iterator first, string_iterator last);
@@ -56,26 +56,22 @@ namespace quickbook
struct snippet_data
{
- snippet_data(std::string const& id, int callout_base_id)
+ snippet_data(std::string const& id)
: id(id)
- , callout_base_id(callout_base_id)
, start_code(false)
{}
std::string id;
- int callout_base_id;
bool start_code;
std::string::const_iterator source_pos;
mapped_file_builder::pos start_pos;
- value_builder callouts;
boost::shared_ptr<snippet_data> next;
};
- void push_snippet_data(std::string const& id, int callout_base_id,
+ void push_snippet_data(std::string const& id,
std::string::const_iterator pos)
{
- boost::shared_ptr<snippet_data> new_snippet(
- new snippet_data(id, callout_base_id));
+ boost::shared_ptr<snippet_data> new_snippet(new snippet_data(id));
new_snippet->next = snippet_stack;
snippet_stack = new_snippet;
snippet_stack->start_code = in_code;
@@ -95,7 +91,6 @@ namespace quickbook
std::string::const_iterator mark_begin, mark_end;
std::string::const_iterator last_code_pos;
bool in_code;
- int callout_id;
boost::shared_ptr<snippet_data> snippet_stack;
std::vector<template_symbol>& storage;
file_ptr source_file;
@@ -240,8 +235,6 @@ namespace quickbook
| escaped_comment [boost::bind(&actions_type::escaped_comment, &actions, _1, _2)]
| ignore [boost::bind(&actions_type::append_code, &actions, _1, _2)]
| pass_thru_comment [boost::bind(&actions_type::pass_thru, &actions, _1, _2)]
- | line_callout [boost::bind(&actions_type::callout, &actions, _1, _2)]
- | inline_callout [boost::bind(&actions_type::callout, &actions, _1, _2)]
| cl::anychar_p
;
@@ -287,23 +280,6 @@ namespace quickbook
"/*[*/"
;
- inline_callout
- = cl::confix_p(
- "/*<" >> *cl::space_p,
- (*cl::anychar_p) [boost::bind(&actions_type::mark, &actions, _1, _2)],
- ">*/"
- )
- ;
-
- line_callout
- = cl::confix_p(
- "/*<<" >> *cl::space_p,
- (*cl::anychar_p) [boost::bind(&actions_type::mark, &actions, _1, _2)],
- ">>*/"
- )
- >> *cl::space_p
- ;
-
ignore
= cl::confix_p(
*cl::blank_p >> "//<-",
@@ -354,7 +330,7 @@ namespace quickbook
cl::rule<Scanner>
start_, identifier, code_elements, start_snippet, end_snippet,
- escaped_comment, pass_thru_comment, inline_callout, line_callout, ignore;
+ escaped_comment, pass_thru_comment, ignore;
cl::rule<Scanner> const&
start() const { return start_; }
@@ -447,27 +423,6 @@ namespace quickbook
content.add(mark_begin, mark_end);
}
- void code_snippet_actions::callout(string_iterator first, string_iterator last)
- {
- if(!snippet_stack) return;
- append_code(first, last);
-
- if (!in_code)
- {
- content.add("\n\n", first);
- content.add(source_type, first);
- content.add("```\n", first);
- in_code = true;
- }
-
- content.add(
- "``[[callout" + boost::lexical_cast<std::string>(callout_id) + "]]``",
- first);
-
- snippet_stack->callouts.insert(qbk_value(source_file, mark_begin, mark_end, template_tags::block));
- ++callout_id;
- }
-
void code_snippet_actions::escaped_comment(string_iterator first, string_iterator last)
{
append_code(first, last);
@@ -529,7 +484,7 @@ namespace quickbook
if (qbk_version_n >= 106u) {
detail::outerr(source_file->path)
<< "Unclosed snippet '"
- << detail::utf8(snippet_stack->id)
+ << snippet_stack->id
<< "'"
<< std::endl;
++error_count;
@@ -537,7 +492,7 @@ namespace quickbook
else {
detail::outwarn(source_file->path)
<< "Unclosed snippet '"
- << detail::utf8(snippet_stack->id)
+ << snippet_stack->id
<< "'"
<< std::endl;
}
@@ -549,7 +504,7 @@ namespace quickbook
void code_snippet_actions::start_snippet_impl(std::string const& id,
string_iterator position)
{
- push_snippet_data(id, callout_id, position);
+ push_snippet_data(id, position);
}
void code_snippet_actions::end_snippet_impl(string_iterator position)
@@ -557,7 +512,6 @@ namespace quickbook
assert(snippet_stack);
boost::shared_ptr<snippet_data> snippet = pop_snippet_data();
- value callouts = snippet->callouts.release();
mapped_file_builder f;
f.start(source_file);
@@ -572,29 +526,11 @@ namespace quickbook
}
std::vector<std::string> params;
- int i = 0;
- for(value::iterator it = callouts.begin(); it != callouts.end(); ++it)
- {
- params.push_back("[callout" + boost::lexical_cast<std::string>(snippet->callout_base_id + i) + "]");
- ++i;
- }
file_ptr body = f.release();
- value_builder builder;
- builder.set_tag(template_tags::snippet);
- builder.insert(qbk_value(body, body->source.begin(), body->source.end(),
- template_tags::block));
- builder.insert(callouts);
-
- template_symbol symbol(snippet->id, params, builder.release());
- storage.push_back(symbol);
-
- // Copy the snippet's callouts to its parent
-
- if(snippet_stack)
- {
- snippet_stack->callouts.extend(callouts);
- }
+ storage.push_back(template_symbol(snippet->id, params,
+ qbk_value(body, body->source.begin(), body->source.end(),
+ template_tags::snippet)));
}
}
diff --git a/tools/quickbook/src/doc_info_actions.cpp b/tools/quickbook/src/doc_info_actions.cpp
index e23466fd3d..42ee961832 100644
--- a/tools/quickbook/src/doc_info_actions.cpp
+++ b/tools/quickbook/src/doc_info_actions.cpp
@@ -12,12 +12,13 @@
#include <boost/bind.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
-#include <boost/filesystem/v3/operations.hpp>
+#include <boost/filesystem/operations.hpp>
#include "quickbook.hpp"
#include "utils.hpp"
#include "files.hpp"
#include "input_path.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "doc_info_tags.hpp"
#include "id_manager.hpp"
@@ -75,7 +76,7 @@ namespace quickbook
}
// Any number of attributes, so stuff them into a vector.
- std::vector<value> consume_multiple_lists(value_consumer& c, value::tag_type tag)
+ std::vector<value> consume_multiple_values(value_consumer& c, value::tag_type tag)
{
std::vector<value> values;
@@ -86,7 +87,7 @@ namespace quickbook
return values;
}
- unsigned get_version(quickbook::actions& actions, bool using_docinfo,
+ unsigned get_version(quickbook::state& state, bool using_docinfo,
value version)
{
unsigned result = 0;
@@ -103,15 +104,15 @@ namespace quickbook
result = ((unsigned) major_verison * 100) +
(unsigned) minor_verison;
- if(result < 100 || result > 106)
+ if(result < 100 || result > 107)
{
- detail::outerr(actions.current_file->path)
+ detail::outerr(state.current_file->path)
<< "Unknown version: "
<< major_verison
<< "."
<< minor_verison
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
}
}
}
@@ -119,7 +120,7 @@ namespace quickbook
return result;
}
- std::string pre(quickbook::actions& actions, parse_iterator pos,
+ std::string pre(quickbook::state& state, parse_iterator pos,
value include_doc_id, bool nested_file)
{
// The doc_info in the file has been parsed. Here's what we'll do
@@ -128,7 +129,7 @@ namespace quickbook
// If there isn't a doc info block, then values will be empty, so most
// of the following code won't actually do anything.
- value_consumer values = actions.values.release();
+ value_consumer values = state.values.release();
// Skip over invalid attributes
@@ -148,15 +149,15 @@ namespace quickbook
{
if (!nested_file)
{
- detail::outerr(actions.current_file, pos.base())
+ detail::outerr(state.current_file, pos.base())
<< "No doc_info block."
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
// Create a fake document info block in order to continue.
doc_type = "article";
- doc_title = qbk_value(actions.current_file,
+ doc_title = qbk_value(state.current_file,
pos.base(), pos.base(),
doc_info_tags::type);
use_doc_info = true;
@@ -165,31 +166,33 @@ namespace quickbook
std::vector<std::string> duplicates;
+ std::vector<value> escaped_attributes = consume_multiple_values(values, doc_info_tags::escaped_attribute);
+
value qbk_version = consume_list(values, doc_attributes::qbk_version, &duplicates);
value compatibility_mode = consume_list(values, doc_attributes::compatibility_mode, &duplicates);
- consume_multiple_lists(values, doc_attributes::source_mode);
+ consume_multiple_values(values, doc_attributes::source_mode);
value id = consume_value_in_list(values, doc_info_attributes::id, &duplicates);
value dirname = consume_value_in_list(values, doc_info_attributes::dirname, &duplicates);
value last_revision = consume_value_in_list(values, doc_info_attributes::last_revision, &duplicates);
value purpose = consume_value_in_list(values, doc_info_attributes::purpose, &duplicates);
- std::vector<value> categories = consume_multiple_lists(values, doc_info_attributes::category);
+ std::vector<value> categories = consume_multiple_values(values, doc_info_attributes::category);
value lang = consume_value_in_list(values, doc_info_attributes::lang, &duplicates);
value version = consume_value_in_list(values, doc_info_attributes::version, &duplicates);
- std::vector<value> authors = consume_multiple_lists(values, doc_info_attributes::authors);
- std::vector<value> copyrights = consume_multiple_lists(values, doc_info_attributes::copyright);
+ std::vector<value> authors = consume_multiple_values(values, doc_info_attributes::authors);
+ std::vector<value> copyrights = consume_multiple_values(values, doc_info_attributes::copyright);
value license = consume_value_in_list(values, doc_info_attributes::license, &duplicates);
- std::vector<value> biblioids = consume_multiple_lists(values, doc_info_attributes::biblioid);
+ std::vector<value> biblioids = consume_multiple_values(values, doc_info_attributes::biblioid);
value xmlbase = consume_value_in_list(values, doc_info_attributes::xmlbase, &duplicates);
values.finish();
if(!duplicates.empty())
{
- detail::outwarn(actions.current_file->path)
+ detail::outwarn(state.current_file->path)
<< (duplicates.size() > 1 ?
"Duplicate attributes" : "Duplicate attribute")
- << ":" << detail::utf8(boost::algorithm::join(duplicates, ", "))
+ << ":" << boost::algorithm::join(duplicates, ", ")
<< "\n"
;
}
@@ -203,12 +206,13 @@ namespace quickbook
// Quickbook version
- unsigned new_version = get_version(actions, use_doc_info, qbk_version);
+ unsigned new_version = get_version(state, use_doc_info, qbk_version);
- if (new_version != qbk_version_n && new_version == 106)
+ if (new_version != qbk_version_n && new_version >= 106)
{
- detail::outwarn(actions.current_file->path)
- << "Quickbook 1.6 is still under development and is "
+ detail::outwarn(state.current_file->path)
+ << "Quickbook " << (new_version / 100) << "." << (new_version % 100)
+ << " is still under development and is "
"likely to change in the future." << std::endl;
}
@@ -218,34 +222,34 @@ namespace quickbook
else if (use_doc_info) {
// hard code quickbook version to v1.1
qbk_version_n = 101;
- detail::outwarn(actions.current_file, pos.base())
+ detail::outwarn(state.current_file, pos.base())
<< "Quickbook version undefined. "
"Version 1.1 is assumed" << std::endl;
}
- actions.current_file->version(qbk_version_n);
+ state.current_file->version(qbk_version_n);
// Compatibility Version
unsigned compatibility_version =
- get_version(actions, use_doc_info, compatibility_mode);
+ get_version(state, use_doc_info, compatibility_mode);
if (!compatibility_version) {
compatibility_version = use_doc_info ?
- qbk_version_n : actions.ids.compatibility_version();
+ qbk_version_n : state.ids.compatibility_version();
}
// Start file, finish here if not generating document info.
if (!use_doc_info)
{
- actions.ids.start_file(compatibility_version, include_doc_id_, id_,
+ state.ids.start_file(compatibility_version, include_doc_id_, id_,
doc_title);
return "";
}
std::string id_placeholder =
- actions.ids.start_file_with_docinfo(
+ state.ids.start_file_with_docinfo(
compatibility_version, include_doc_id_, id_, doc_title);
// Make sure we really did have a document info block.
@@ -258,22 +262,22 @@ namespace quickbook
if (!xmlbase.empty())
{
- xinclude_path x = calculate_xinclude_path(xmlbase, actions);
+ xinclude_path x = calculate_xinclude_path(xmlbase, state);
if (!fs::is_directory(x.path))
{
detail::outerr(xmlbase.get_file(), xmlbase.get_position())
<< "xmlbase \""
- << detail::utf8(xmlbase.get_quickbook())
+ << xmlbase.get_quickbook()
<< "\" isn't a directory."
<< std::endl;
- ++actions.error_count;
+ ++state.error_count;
}
else
{
xmlbase_value = x.uri;
- actions.xinclude_base = x.path;
+ state.xinclude_base = x.path;
}
}
@@ -294,11 +298,11 @@ namespace quickbook
if(!invalid_attributes.empty())
{
- detail::outwarn(actions.current_file->path)
+ detail::outwarn(state.current_file->path)
<< (invalid_attributes.size() > 1 ?
"Invalid attributes" : "Invalid attribute")
- << " for '" << detail::utf8(doc_type) << " document info': "
- << detail::utf8(boost::algorithm::join(invalid_attributes, ", "))
+ << " for '" << doc_type << " document info': "
+ << boost::algorithm::join(invalid_attributes, ", ")
<< "\n"
;
}
@@ -308,7 +312,7 @@ namespace quickbook
if (!nested_file)
{
- actions.out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ state.out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
<< "<!DOCTYPE "
<< doc_type
<< " PUBLIC \"-//Boost//DTD BoostBook XML V1.0//EN\"\n"
@@ -316,51 +320,51 @@ namespace quickbook
;
}
- actions.out << '<' << doc_type << "\n"
+ state.out << '<' << doc_type << "\n"
<< " id=\""
<< id_placeholder
<< "\"\n";
if(!lang.empty())
{
- actions.out << " lang=\""
+ state.out << " lang=\""
<< doc_info_output(lang, 106)
<< "\"\n";
}
if(doc_type == "library" && !doc_title.empty())
{
- actions.out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n";
+ state.out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n";
}
// Set defaults for dirname + last_revision
if (!dirname.empty() || doc_type == "library")
{
- actions.out << " dirname=\"";
+ state.out << " dirname=\"";
if (!dirname.empty()) {
- actions.out << doc_info_output(dirname, 106);
+ state.out << doc_info_output(dirname, 106);
}
else if (!id_.empty()) {
- actions.out << id_;
+ state.out << id_;
}
else if (!include_doc_id_.empty()) {
- actions.out << include_doc_id_;
+ state.out << include_doc_id_;
}
else if (!doc_title.empty()) {
- actions.out << detail::make_identifier(doc_title.get_quickbook());
+ state.out << detail::make_identifier(doc_title.get_quickbook());
}
else {
- actions.out << "library";
+ state.out << "library";
}
- actions.out << "\"\n";
+ state.out << "\"\n";
}
- actions.out << " last-revision=\"";
+ state.out << " last-revision=\"";
if (!last_revision.empty())
{
- actions.out << doc_info_output(last_revision, 106);
+ state.out << doc_info_output(last_revision, 106);
}
else
{
@@ -375,19 +379,19 @@ namespace quickbook
current_gm_time
);
- actions.out << strdate;
+ state.out << strdate;
}
- actions.out << "\" \n";
+ state.out << "\" \n";
if (!xmlbase.empty())
{
- actions.out << " xml:base=\""
+ state.out << " xml:base=\""
<< xmlbase_value
<< "\"\n";
}
- actions.out << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n";
+ state.out << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n";
std::ostringstream tmp;
@@ -429,9 +433,9 @@ namespace quickbook
year_start;
if (year_end < year_start) {
- ++actions.error_count;
+ ++state.error_count;
- detail::outerr(actions.current_file, copyright.begin()->get_position())
+ detail::outerr(state.current_file, copyright.begin()->get_position())
<< "Invalid year range: "
<< year_start
<< "-"
@@ -456,7 +460,7 @@ namespace quickbook
if (!license.empty())
{
tmp << " <legalnotice id=\""
- << actions.ids.add_id("legal", id_category::generated)
+ << state.ids.add_id("legal", id_category::generated)
<< "\">\n"
<< " <para>\n"
<< " " << doc_info_output(license, 103) << "\n"
@@ -502,14 +506,22 @@ namespace quickbook
biblioid.finish();
}
+ BOOST_FOREACH(value escaped, escaped_attributes)
+ {
+ tmp << "<!--quickbook-escape-prefix-->"
+ << escaped.get_quickbook()
+ << "<!--quickbook-escape-postfix-->"
+ ;
+ }
+
if(doc_type != "library") {
- write_document_title(actions.out, doc_title, version);
+ write_document_title(state.out, doc_title, version);
}
std::string docinfo = tmp.str();
if(!docinfo.empty())
{
- actions.out << " <" << doc_type << "info>\n"
+ state.out << " <" << doc_type << "info>\n"
<< docinfo
<< " </" << doc_type << "info>\n"
<< "\n"
@@ -517,31 +529,31 @@ namespace quickbook
}
if(doc_type == "library") {
- write_document_title(actions.out, doc_title, version);
+ write_document_title(state.out, doc_title, version);
}
return doc_type;
}
- void post(quickbook::actions& actions, std::string const& doc_type)
+ void post(quickbook::state& state, std::string const& doc_type)
{
// We've finished generating our output. Here's what we'll do
// *after* everything else.
// Close any open sections.
- if (!doc_type.empty() && actions.ids.section_level() > 1) {
- detail::outwarn(actions.current_file->path)
+ if (!doc_type.empty() && state.ids.section_level() > 1) {
+ detail::outwarn(state.current_file->path)
<< "Missing [endsect] detected at end of file."
<< std::endl;
- while(actions.ids.section_level() > 1) {
- actions.out << "</section>";
- actions.ids.end_section();
+ while(state.ids.section_level() > 1) {
+ state.out << "</section>";
+ state.ids.end_section();
}
}
- actions.ids.end_file();
- if (!doc_type.empty()) actions.out << "\n</" << doc_type << ">\n\n";
+ state.ids.end_file();
+ if (!doc_type.empty()) state.out << "\n</" << doc_type << ">\n\n";
}
static void write_document_title(collector& out, value const& title, value const& version)
diff --git a/tools/quickbook/src/doc_info_grammar.cpp b/tools/quickbook/src/doc_info_grammar.cpp
index 26418eec48..862d0ce57a 100644
--- a/tools/quickbook/src/doc_info_grammar.cpp
+++ b/tools/quickbook/src/doc_info_grammar.cpp
@@ -19,7 +19,8 @@
#include <boost/spirit/include/phoenix1_primitives.hpp>
#include <boost/spirit/include/phoenix1_operators.hpp>
#include "grammar_impl.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "doc_info_tags.hpp"
#include "phrase_tags.hpp"
@@ -69,6 +70,7 @@ namespace quickbook
cl::rule<scanner>
doc_info_block, doc_attribute, doc_info_attribute,
+ doc_info_escaped_attributes,
doc_title, doc_simple, doc_phrase, doc_fallback,
doc_authors, doc_author,
doc_copyright, doc_copyright_holder,
@@ -113,6 +115,11 @@ namespace quickbook
BOOST_FOREACH(value::tag_type t, doc_info_attributes::tags()) {
local.doc_info_attributes.add(doc_info_attributes::name(t), t);
}
+
+ // Actions
+ error_action error(state);
+ plain_char_action plain_char(state.phrase, state);
+ scoped_parser<to_value_scoped_action> to_value(state);
doc_info_details =
space [ph::var(local.source_mode_unset) = true]
@@ -126,9 +133,9 @@ namespace quickbook
'['
>> space
>> (local.doc_types >> cl::eps_p)
- [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)]
+ [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)]
>> hard_space
- >> actions.to_value(doc_info_tags::title)
+ >> to_value(doc_info_tags::title)
[ *( ~cl::eps_p(blank >> (cl::ch_p('[') | ']' | cl::eol_p))
>> local.char_
)
@@ -137,15 +144,18 @@ namespace quickbook
>> blank
]
>> space
- >> !(qbk_since(106u) >> cl::eps_p(ph::var(local.source_mode_unset))
- [cl::assign_a(actions.source_mode, "c++")]
+ >> !(qbk_ver(106u) >> cl::eps_p(ph::var(local.source_mode_unset))
+ [cl::assign_a(state.source_mode, "c++")]
)
- >> (*( local.doc_info_attribute
- >> space
- )) [actions.values.sort()]
+ >> ( *( ( local.doc_info_attribute
+ | local.doc_info_escaped_attributes
+ )
+ >> space
+ )
+ ) [state.values.sort()]
>> ( ']'
>> (+eol | cl::end_p)
- | cl::eps_p [actions.error]
+ | cl::eps_p [error]
)
;
@@ -154,8 +164,8 @@ namespace quickbook
>> space
>> local.doc_attributes [local.assign_attribute]
>> hard_space
- >> actions.values.list(ph::var(local.attribute_tag))
- [ cl::eps_p [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)]
+ >> state.values.list(ph::var(local.attribute_tag))
+ [ cl::eps_p [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)]
>> local.attribute_rule
]
>> space
@@ -169,33 +179,41 @@ namespace quickbook
[local.assign_attribute]
| (+(cl::alnum_p | '_' | '-'))
[local.fallback_attribute]
- [actions.error("Unrecognized document attribute: '%s'.")]
+ [error("Unrecognized document attribute: '%s'.")]
)
>> hard_space
- >> actions.values.list(ph::var(local.attribute_tag))
+ >> state.values.list(ph::var(local.attribute_tag))
[local.attribute_rule]
>> space
>> ']'
;
- local.doc_fallback = actions.to_value() [
+ local.doc_fallback = to_value() [
*(~cl::eps_p(']') >> local.char_)
];
+ local.doc_info_escaped_attributes =
+ ("'''" >> !eol)
+ >> (*(cl::anychar_p - "'''")) [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::escaped_attribute)]
+ >> ( cl::str_p("'''")
+ | cl::eps_p [error("Unclosed boostbook escape.")]
+ )
+ ;
+
// Document Attributes
local.quickbook_version =
- cl::uint_p [actions.values.entry(ph::arg1)]
+ cl::uint_p [state.values.entry(ph::arg1)]
>> '.'
- >> uint2_t() [actions.values.entry(ph::arg1)]
+ >> uint2_t() [state.values.entry(ph::arg1)]
;
local.attribute_rules[doc_attributes::qbk_version] = &local.quickbook_version;
local.doc_compatibility_mode =
- cl::uint_p [actions.values.entry(ph::arg1)]
+ cl::uint_p [state.values.entry(ph::arg1)]
>> '.'
- >> uint2_t() [actions.values.entry(ph::arg1)]
+ >> uint2_t() [state.values.entry(ph::arg1)]
;
local.attribute_rules[doc_attributes::compatibility_mode] = &local.doc_compatibility_mode;
@@ -205,7 +223,7 @@ namespace quickbook
cl::str_p("c++")
| "python"
| "teletype"
- ) [cl::assign_a(actions.source_mode)]
+ ) [cl::assign_a(state.source_mode)]
[ph::var(local.source_mode_unset) = false]
;
@@ -213,7 +231,7 @@ namespace quickbook
// Document Info Attributes
- local.doc_simple = actions.to_value() [*(~cl::eps_p(']') >> local.char_)];
+ local.doc_simple = to_value() [*(~cl::eps_p(']') >> local.char_)];
local.attribute_rules[doc_info_attributes::version] = &local.doc_simple;
local.attribute_rules[doc_info_attributes::id] = &local.doc_simple;
local.attribute_rules[doc_info_attributes::dirname] = &local.doc_simple;
@@ -232,18 +250,18 @@ namespace quickbook
local.doc_copyright =
*( +( local.doc_copyright_year
- [actions.values.entry(ph::arg1, doc_info_tags::copyright_year)]
+ [state.values.entry(ph::arg1, doc_info_tags::copyright_year)]
>> space
>> !( '-'
>> space
>> local.doc_copyright_year
- [actions.values.entry(ph::arg1, doc_info_tags::copyright_year_end)]
+ [state.values.entry(ph::arg1, doc_info_tags::copyright_year_end)]
>> space
)
>> !cl::ch_p(',')
>> space
)
- >> actions.to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ]
+ >> to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ]
>> !cl::ch_p(',')
>> space
)
@@ -251,17 +269,17 @@ namespace quickbook
local.attribute_rules[doc_info_attributes::copyright] = &local.doc_copyright;
- local.doc_phrase = actions.to_value() [ nested_phrase ];
+ local.doc_phrase = to_value() [ nested_phrase ];
local.attribute_rules[doc_info_attributes::purpose] = &local.doc_phrase;
local.attribute_rules[doc_info_attributes::license] = &local.doc_phrase;
local.doc_author =
'['
>> space
- >> actions.to_value(doc_info_tags::author_surname)
+ >> to_value(doc_info_tags::author_surname)
[*(~cl::eps_p(',') >> local.char_)]
>> ',' >> space
- >> actions.to_value(doc_info_tags::author_first)
+ >> to_value(doc_info_tags::author_first)
[*(~cl::eps_p(']') >> local.char_)]
>> ']'
;
@@ -276,14 +294,14 @@ namespace quickbook
local.attribute_rules[doc_info_attributes::authors] = &local.doc_authors;
local.doc_biblioid =
- (+cl::alnum_p) [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)]
+ (+cl::alnum_p) [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)]
>> hard_space
- >> actions.to_value(doc_info_tags::biblioid_value)
+ >> to_value(doc_info_tags::biblioid_value)
[+(~cl::eps_p(']') >> local.char_)]
;
local.attribute_rules[doc_info_attributes::biblioid] = &local.doc_biblioid;
- local.char_ = escape | cl::anychar_p[actions.plain_char];
+ local.char_ = escape | cl::anychar_p[plain_char];
}
}
diff --git a/tools/quickbook/src/doc_info_tags.hpp b/tools/quickbook/src/doc_info_tags.hpp
index 4caea3317c..ccc69186cb 100644
--- a/tools/quickbook/src/doc_info_tags.hpp
+++ b/tools/quickbook/src/doc_info_tags.hpp
@@ -21,6 +21,7 @@ namespace quickbook
(copyright_year)(copyright_year_end)(copyright_name)
(license)
(biblioid_class)(biblioid_value)
+ (escaped_attribute)
)
QUICKBOOK_VALUE_NAMED_TAGS(doc_attributes, 0x440,
diff --git a/tools/quickbook/src/files.cpp b/tools/quickbook/src/files.cpp
index ce63c84eb2..f85b611623 100644
--- a/tools/quickbook/src/files.cpp
+++ b/tools/quickbook/src/files.cpp
@@ -8,10 +8,11 @@
http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#include "files.hpp"
-#include <boost/filesystem/v3/fstream.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/unordered_map.hpp>
#include <boost/range/algorithm/upper_bound.hpp>
#include <boost/range/algorithm/transform.hpp>
+#include <boost/foreach.hpp>
#include <fstream>
#include <iterator>
@@ -285,8 +286,9 @@ namespace quickbook
struct mapped_file : file
{
mapped_file(file_ptr original) :
- file(original->path, std::string(), original->version()),
- original(original), mapped_sections() {}
+ file(*original, std::string()),
+ original(original), mapped_sections()
+ {}
file_ptr original;
std::vector<mapped_file_section> mapped_sections;
diff --git a/tools/quickbook/src/files.hpp b/tools/quickbook/src/files.hpp
index 1b0ef282b0..4f217e70cd 100644
--- a/tools/quickbook/src/files.hpp
+++ b/tools/quickbook/src/files.hpp
@@ -12,11 +12,10 @@
#define BOOST_QUICKBOOK_FILES_HPP
#include <string>
-#include <boost/filesystem/v3/path.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/intrusive_ptr.hpp>
#include <stdexcept>
#include <cassert>
-#include "intrusive_base.hpp"
namespace quickbook {
@@ -34,20 +33,35 @@ namespace quickbook {
int column;
};
- struct file : intrusive_base<file>
+ struct file
{
+ private:
+ // Non copyable
+ file& operator=(file const&);
+ file(file const&);
+ public:
fs::path const path;
std::string source;
+ bool is_code_snippets;
private:
unsigned qbk_version;
+ unsigned ref_count;
public:
file(fs::path const& path, std::string const& source,
unsigned qbk_version) :
- path(path), source(source), qbk_version(qbk_version)
+ path(path), source(source), is_code_snippets(false),
+ qbk_version(qbk_version), ref_count(0)
{}
- virtual ~file() {}
+ file(file const& f, std::string const& source) :
+ path(f.path), source(source), is_code_snippets(f.is_code_snippets),
+ qbk_version(f.qbk_version), ref_count(0)
+ {}
+
+ virtual ~file() {
+ assert(!ref_count);
+ }
unsigned version() const {
assert(qbk_version);
@@ -63,6 +77,11 @@ namespace quickbook {
}
virtual file_position position_of(std::string::const_iterator) const;
+
+ friend void intrusive_ptr_add_ref(file* ptr) { ++ptr->ref_count; }
+
+ friend void intrusive_ptr_release(file* ptr)
+ { if(--ptr->ref_count == 0) delete ptr; }
};
// If version isn't supplied then it must be set later.
diff --git a/tools/quickbook/src/fwd.hpp b/tools/quickbook/src/fwd.hpp
index 7995c14097..7cccde8735 100644
--- a/tools/quickbook/src/fwd.hpp
+++ b/tools/quickbook/src/fwd.hpp
@@ -16,12 +16,13 @@
namespace quickbook
{
- struct actions;
+ struct state;
struct quickbook_grammar;
struct collector;
struct id_manager;
struct section_info;
struct file;
+ struct template_symbol;
typedef boost::intrusive_ptr<file> file_ptr;
typedef std::string::const_iterator string_iterator;
diff --git a/tools/quickbook/src/grammar.cpp b/tools/quickbook/src/grammar.cpp
index a0e2e57887..8f244f18ac 100644
--- a/tools/quickbook/src/grammar.cpp
+++ b/tools/quickbook/src/grammar.cpp
@@ -13,8 +13,8 @@
namespace quickbook
{
- quickbook_grammar::quickbook_grammar(quickbook::actions& a)
- : impl_(new impl(a))
+ quickbook_grammar::quickbook_grammar(quickbook::state& s)
+ : impl_(new impl(s))
, command_line_macro(impl_->command_line, "command_line_macro")
, inline_phrase(impl_->inline_phrase, "inline_phrase")
, phrase(impl_->phrase_start, "phrase")
@@ -27,8 +27,8 @@ namespace quickbook
{
}
- quickbook_grammar::impl::impl(quickbook::actions& a)
- : actions(a)
+ quickbook_grammar::impl::impl(quickbook::state& s)
+ : state(s)
, cleanup_()
{
init_main();
diff --git a/tools/quickbook/src/grammar.hpp b/tools/quickbook/src/grammar.hpp
index 73aae4a26c..54aaf2b3ea 100644
--- a/tools/quickbook/src/grammar.hpp
+++ b/tools/quickbook/src/grammar.hpp
@@ -62,7 +62,7 @@ namespace quickbook
grammar block;
grammar doc_info;
- quickbook_grammar(quickbook::actions&);
+ quickbook_grammar(quickbook::state&);
~quickbook_grammar();
};
}
diff --git a/tools/quickbook/src/grammar_impl.hpp b/tools/quickbook/src/grammar_impl.hpp
index c968111b8c..090b399048 100644
--- a/tools/quickbook/src/grammar_impl.hpp
+++ b/tools/quickbook/src/grammar_impl.hpp
@@ -38,6 +38,7 @@ namespace quickbook
in_block = phrase | maybe_block | nested_block | conditional_or_block | block,
only_nested_block = nested_block,
only_block = nested_block | conditional_or_block | block,
+ only_list_block = nested_block | conditional_or_block,
only_contextual_block = maybe_block | nested_block | conditional_or_block | block
};
@@ -59,7 +60,7 @@ namespace quickbook
struct quickbook_grammar::impl
{
- quickbook::actions& actions;
+ quickbook::state& state;
cleanup cleanup_;
// Main Grammar
@@ -73,6 +74,7 @@ namespace quickbook
cl::rule<scanner> inside_preformatted;
cl::rule<scanner> inside_paragraph;
cl::rule<scanner> command_line;
+ cl::rule<scanner> attribute_value_1_7;
cl::rule<scanner> escape;
cl::rule<scanner> raw_escape;
@@ -92,7 +94,7 @@ namespace quickbook
// Doc Info
cl::rule<scanner> doc_info_details;
- impl(quickbook::actions&);
+ impl(quickbook::state&);
private:
diff --git a/tools/quickbook/src/id_manager.cpp b/tools/quickbook/src/id_manager.cpp
index 32e537df71..3b2f601a11 100644
--- a/tools/quickbook/src/id_manager.cpp
+++ b/tools/quickbook/src/id_manager.cpp
@@ -9,8 +9,7 @@
#include "id_manager.hpp"
#include "utils.hpp"
#include "string_ref.hpp"
-#include "intrusive_base.hpp"
-#include <boost/intrusive_ptr.hpp>
+#include <boost/make_shared.hpp>
#include <boost/unordered_map.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range/algorithm.hpp>
@@ -113,7 +112,7 @@ namespace quickbook
struct id_state
{
- boost::intrusive_ptr<file_info> current_file;
+ boost::shared_ptr<file_info> current_file;
std::deque<id_placeholder> placeholders;
// Placeholder methods
@@ -149,25 +148,25 @@ private:
id_placeholder* add_id_to_section(
std::string const& id,
id_category category,
- boost::intrusive_ptr<section_info> const& section);
+ boost::shared_ptr<section_info> const& section);
id_placeholder* create_new_section(
std::string const& id,
id_category category);
void switch_section(id_placeholder*);
- void reswitch_sections(boost::intrusive_ptr<section_info> const&,
- boost::intrusive_ptr<section_info> const&);
+ void reswitch_sections(boost::shared_ptr<section_info> const&,
+ boost::shared_ptr<section_info> const&);
void restore_section();
};
- struct file_info : intrusive_base<file_info>
+ struct file_info
{
- boost::intrusive_ptr<file_info> parent;
- boost::intrusive_ptr<doc_info> document;
+ boost::shared_ptr<file_info> parent;
+ boost::shared_ptr<doc_info> document;
bool document_root; // !parent || document != parent->document
unsigned compatibility_version;
- boost::intrusive_ptr<section_info> switched_section;
+ boost::shared_ptr<section_info> switched_section;
id_placeholder* original_placeholder;
// The 1.1-1.5 document id would actually change per file due to
@@ -175,15 +174,15 @@ private:
// document title instead of the id.
std::string doc_id_1_1;
- file_info(boost::intrusive_ptr<file_info> const& parent,
+ file_info(boost::shared_ptr<file_info> const& parent,
unsigned compatibility_version) :
parent(parent), document(parent->document), document_root(false),
compatibility_version(compatibility_version),
switched_section(), original_placeholder()
{}
- file_info(boost::intrusive_ptr<file_info> const& parent,
- boost::intrusive_ptr<doc_info> const& document,
+ file_info(boost::shared_ptr<file_info> const& parent,
+ boost::shared_ptr<doc_info> const& document,
unsigned compatibility_version) :
parent(parent), document(document), document_root(true),
compatibility_version(compatibility_version),
@@ -191,9 +190,9 @@ private:
{}
};
- struct doc_info : intrusive_base<doc_info>
+ struct doc_info
{
- boost::intrusive_ptr<section_info> current_section;
+ boost::shared_ptr<section_info> current_section;
std::string last_title_1_1;
std::string section_id_1_1;
@@ -202,15 +201,15 @@ private:
{}
};
- struct section_info : intrusive_base<section_info>
+ struct section_info
{
- boost::intrusive_ptr<section_info> parent;
+ boost::shared_ptr<section_info> parent;
unsigned compatibility_version;
unsigned level;
std::string id_1_1;
id_placeholder* placeholder_1_6;
- section_info(boost::intrusive_ptr<section_info> const& parent,
+ section_info(boost::shared_ptr<section_info> const& parent,
unsigned compatibility_version, std::string const& id) :
parent(parent), compatibility_version(compatibility_version),
level(parent ? parent->level + 1 : 1),
@@ -394,11 +393,11 @@ private:
}
void id_state::reswitch_sections(
- boost::intrusive_ptr<section_info> const& popped_section,
- boost::intrusive_ptr<section_info> const& parent_section)
+ boost::shared_ptr<section_info> const& popped_section,
+ boost::shared_ptr<section_info> const& parent_section)
{
- boost::intrusive_ptr<file_info> file = current_file;
- boost::intrusive_ptr<file_info> first_switched_file;
+ boost::shared_ptr<file_info> file = current_file;
+ boost::shared_ptr<file_info> first_switched_file;
for (;;) {
if (file->switched_section == popped_section)
@@ -436,15 +435,16 @@ private:
{
// Create new file
- boost::intrusive_ptr<file_info> parent = current_file;
+ boost::shared_ptr<file_info> parent = current_file;
if (document_root) {
- current_file = new file_info(parent, new doc_info(),
+ current_file = boost::make_shared<file_info>(parent,
+ boost::make_shared<doc_info>(),
compatibility_version);
}
else {
current_file =
- new file_info(parent, compatibility_version);
+ boost::make_shared<file_info>(parent, compatibility_version);
}
// Choose specified id to use. Prefer 'include_doc_id' (the id
@@ -505,7 +505,7 @@ private:
if (compatibility_version >= 106u && !initial_doc_id.empty()) {
switch_section(add_id_to_section(initial_doc_id,
id_category::explicit_section_id,
- boost::intrusive_ptr<section_info>()));
+ boost::shared_ptr<section_info>()));
}
return 0;
@@ -529,7 +529,7 @@ private:
id_placeholder* id_state::add_id_to_section(
std::string const& id,
id_category category,
- boost::intrusive_ptr<section_info> const& section)
+ boost::shared_ptr<section_info> const& section)
{
std::string id_part = id;
@@ -583,11 +583,12 @@ private:
std::string const& id,
id_category category)
{
- boost::intrusive_ptr<section_info> parent =
+ boost::shared_ptr<section_info> parent =
current_file->document->current_section;
- boost::intrusive_ptr<section_info> new_section =
- new section_info(parent, current_file->compatibility_version, id);
+ boost::shared_ptr<section_info> new_section =
+ boost::make_shared<section_info>(parent,
+ current_file->compatibility_version, id);
id_placeholder* p;
@@ -630,7 +631,7 @@ private:
void id_state::end_section()
{
- boost::intrusive_ptr<section_info> popped_section =
+ boost::shared_ptr<section_info> popped_section =
current_file->document->current_section;
current_file->document->current_section = popped_section->parent;
@@ -810,7 +811,7 @@ private:
// Data used for generating placeholders that have duplicates.
//
- struct id_generation_data : intrusive_base<id_generation_data>
+ struct id_generation_data
{
id_generation_data(std::string const& src_id)
: child_start(src_id.rfind('.') + 1),
@@ -865,7 +866,7 @@ private:
id_category category; // The highest priority category of the
// placeholders that want to use this id.
bool used; // Whether this id has been used.
- boost::intrusive_ptr<id_generation_data> generation_data;
+ boost::shared_ptr<id_generation_data> generation_data;
// If a duplicates are found, this is
// created to generate new ids.
//
@@ -1036,7 +1037,8 @@ private:
if (!p.data->generation_data)
{
- p.data->generation_data.reset(new id_generation_data(p.id));
+ p.data->generation_data =
+ boost::make_shared<id_generation_data>(p.id);
register_generation_data(p, ids);
}
diff --git a/tools/quickbook/src/input_path.cpp b/tools/quickbook/src/input_path.cpp
index 4523ac6f22..9b6a87784d 100644
--- a/tools/quickbook/src/input_path.cpp
+++ b/tools/quickbook/src/input_path.cpp
@@ -122,7 +122,7 @@ namespace detail {
return fs::path(static_cast<wchar_t*>(ptr));
}
- stream_string path_to_stream(fs::path const& path)
+ ostream::string path_to_stream(fs::path const& path)
{
cygwin_conv_path_t flags = CCP_WIN_W_TO_POSIX | CCP_RELATIVE;
@@ -145,12 +145,12 @@ namespace detail {
}
#if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS
- stream_string path_to_stream(fs::path const& path)
+ ostream::string path_to_stream(fs::path const& path)
{
return path.string();
}
#else
- stream_string path_to_stream(fs::path const& path)
+ ostream::string path_to_stream(fs::path const& path)
{
return path.native();
}
@@ -166,21 +166,23 @@ namespace detail {
if (_isatty(_fileno(stderr))) _setmode(_fileno(stderr), _O_U16TEXT);
}
- void write_utf8(ostream& out, std::string const& x)
+ void write_utf8(ostream::base_ostream& out, std::string const& x)
{
out << from_utf8(x);
}
ostream& out()
{
- return std::wcout;
+ static ostream x(std::wcout);
+ return x;
}
namespace
{
inline ostream& error_stream()
{
- return std::wcerr;
+ static ostream x(std::wcerr);
+ return x;
}
}
@@ -190,21 +192,23 @@ namespace detail {
{
}
- void write_utf8(ostream& out, std::string const& x)
+ void write_utf8(ostream::base_ostream& out, std::string const& x)
{
out << x;
}
ostream& out()
{
- return std::cout;
+ static ostream x(std::cout);
+ return x;
}
namespace
{
inline ostream& error_stream()
{
- return std::clog;
+ static ostream x(std::clog);
+ return x;
}
}
@@ -254,4 +258,61 @@ namespace detail {
{
return outwarn(f->path, f->position_of(pos).line);
}
+
+ ostream& ostream::operator<<(char c) {
+ assert(c > 0 && c <= 127);
+ base << c;
+ return *this;
+ }
+
+ inline bool check_ascii(char const* x) {
+ for(;*x;++x) if(*x <= 0 || *x > 127) return false;
+ return true;
+ }
+
+ ostream& ostream::operator<<(char const* x) {
+ assert(check_ascii(x));
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(std::string const& x) {
+ write_utf8(base, x);
+ return *this;
+ }
+
+ ostream& ostream::operator<<(int x) {
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(unsigned int x) {
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(long x) {
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(unsigned long x) {
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(fs::path const& x) {
+ base << path_to_stream(x);
+ return *this;
+ }
+
+ ostream& ostream::operator<<(base_ostream& (*x)(base_ostream&)) {
+ base << x;
+ return *this;
+ }
+
+ ostream& ostream::operator<<(base_ios& (*x)(base_ios&)) {
+ base << x;
+ return *this;
+ }
}}
diff --git a/tools/quickbook/src/input_path.hpp b/tools/quickbook/src/input_path.hpp
index a23474d3e1..a9b55f6b2c 100644
--- a/tools/quickbook/src/input_path.hpp
+++ b/tools/quickbook/src/input_path.hpp
@@ -10,7 +10,7 @@
#define BOOST_QUICKBOOK_DETAIL_INPUT_PATH_HPP
#include <boost/config.hpp>
-#include <boost/filesystem/v3/path.hpp>
+#include <boost/filesystem/path.hpp>
#include <string>
#include <stdexcept>
#include <iostream>
@@ -66,17 +66,47 @@ namespace quickbook
typedef std::string input_string;
#endif
+ // A light wrapper around C++'s streams that gets things right
+ // in the quickbook context.
+ //
+ // This is far from perfect but it fixes some issues.
+ struct ostream
+ {
#if QUICKBOOK_WIDE_STREAMS
- typedef std::wostream ostream;
- typedef std::wstring stream_string;
+ typedef std::wostream base_ostream;
+ typedef std::wios base_ios;
+ typedef std::wstring string;
#else
- typedef std::ostream ostream;
- typedef std::string stream_string;
+ typedef std::ostream base_ostream;
+ typedef std::ios base_ios;
+ typedef std::string string;
#endif
+ base_ostream& base;
+
+ explicit ostream(base_ostream& x) : base(x) {}
+
+ // C strings should always be ascii.
+ ostream& operator<<(char);
+ ostream& operator<<(char const*);
+
+ // std::string should be UTF-8 (what a mess!)
+ ostream& operator<<(std::string const&);
+
+ // Other value types.
+ ostream& operator<<(int x);
+ ostream& operator<<(unsigned int x);
+ ostream& operator<<(long x);
+ ostream& operator<<(unsigned long x);
+ ostream& operator<<(fs::path const&);
+
+ // Modifiers
+ ostream& operator<<(base_ostream& (*)(base_ostream&));
+ ostream& operator<<(base_ios& (*)(base_ios&));
+ };
+
std::string input_to_utf8(input_string const&);
fs::path input_to_path(input_string const&);
- stream_string path_to_stream(fs::path const&);
std::string path_to_generic(fs::path const&);
fs::path generic_to_path(std::string const&);
@@ -94,29 +124,6 @@ namespace quickbook
ostream& outwarn(fs::path const& file, int line = -1);
ostream& outerr(file_ptr const&, string_iterator);
ostream& outwarn(file_ptr const&, string_iterator);
-
- struct utf8_proxy
- {
- std::string value;
-
- explicit utf8_proxy(std::string const& v) : value(v) {}
- };
-
- void write_utf8(ostream& out, std::string const&);
-
- inline ostream& operator<<(ostream& out, utf8_proxy const& p) {
- write_utf8(out, p.value);
- return out;
- }
-
- inline utf8_proxy utf8(std::string const& value) {
- return utf8_proxy(value);
- }
-
- template <typename It>
- inline utf8_proxy utf8(It begin, It end) {
- return utf8_proxy(std::string(begin, end));
- }
}
}
diff --git a/tools/quickbook/src/intrusive_base.hpp b/tools/quickbook/src/intrusive_base.hpp
deleted file mode 100644
index 702c13d0b9..0000000000
--- a/tools/quickbook/src/intrusive_base.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*=============================================================================
- Copyright (c) 2011 Daniel James
-
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
-=============================================================================*/
-
-#if !defined(BOOST_QUICKBOOK_INTRUSIVE_BASE_HPP)
-#define BOOST_QUICKBOOK_INTRUSIVE_BASE_HPP
-
-namespace quickbook
-{
- //
- // instructive_base
- //
-
- template <typename T>
- struct intrusive_base
- {
- intrusive_base() : ref_count_(0) {}
- intrusive_base(intrusive_base const&) : ref_count_(0) {}
- intrusive_base& operator=(intrusive_base const&) { return *this; }
- ~intrusive_base() { assert(!ref_count_); }
-
- friend void intrusive_ptr_add_ref(T* ptr)
- { ++ptr->ref_count_; }
-
- friend void intrusive_ptr_release(T* ptr)
- { if(--ptr->ref_count_ == 0) delete ptr; }
- private:
- unsigned ref_count_;
- };
-}
-
-#endif
diff --git a/tools/quickbook/src/main_grammar.cpp b/tools/quickbook/src/main_grammar.cpp
index 1ec2ff9ca8..74dbecea76 100644
--- a/tools/quickbook/src/main_grammar.cpp
+++ b/tools/quickbook/src/main_grammar.cpp
@@ -9,7 +9,8 @@
=============================================================================*/
#include "grammar_impl.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "utils.hpp"
#include "template_tags.hpp"
#include "block_tags.hpp"
@@ -27,8 +28,6 @@
#include <boost/range/algorithm/find_first_of.hpp>
#include <boost/range/as_literal.hpp>
-#include <iostream>
-
namespace quickbook
{
namespace cl = boost::spirit::classic;
@@ -91,44 +90,6 @@ namespace quickbook
string_iterator last);
void clear_stack();
- struct process_element_impl : scoped_action_base {
- process_element_impl(main_grammar_local& l)
- : l(l) {}
-
- bool start()
- {
- if (!(l.info.type & l.element.context()) ||
- qbk_version_n < l.info.qbk_version)
- return false;
-
- info_ = l.info;
-
- if (info_.type != element_info::phrase &&
- info_.type != element_info::maybe_block)
- l.actions_.paragraph();
-
- l.actions_.values.builder.reset();
-
- return true;
- }
-
- template <typename ResultT, typename ScannerT>
- bool result(ResultT result, ScannerT const& scan)
- {
- if (result || info_.type & element_info::in_phrase)
- return result;
-
- l.actions_.error(scan.first, scan.first);
- return true;
- }
-
- void success(parse_iterator, parse_iterator) { l.element_type = info_.type; }
- void failure() { l.element_type = element_info::nothing; }
-
- main_grammar_local& l;
- element_info info_;
- };
-
struct in_list_impl {
main_grammar_local& l;
@@ -216,53 +177,167 @@ namespace quickbook
element_info info;
element_info::type_enum element_type;
- // actions
- quickbook::actions& actions_;
- member_action<main_grammar_local> check_indentation;
- member_action<main_grammar_local> check_code_block;
- member_action<main_grammar_local> start_blocks;
- member_action<main_grammar_local> end_blocks;
- in_list_impl in_list;
- scoped_parser<process_element_impl> process_element;
- scoped_parser<set_no_eols_scoped> scoped_no_eols;
+ // state
+ quickbook::state& state_;
////////////////////////////////////////////////////////////////////////
// Local constructor
- main_grammar_local(quickbook::actions& actions)
+ main_grammar_local(quickbook::state& state)
: list_stack()
, list_indent(0)
, no_eols(true)
- , actions_(actions)
- , check_indentation(*this, &main_grammar_local::check_indentation_impl)
- , check_code_block(*this, &main_grammar_local::check_indentation_impl)
- , start_blocks(*this, &main_grammar_local::start_blocks_impl)
- , end_blocks(*this, &main_grammar_local::end_blocks_impl)
- , in_list(*this)
- , process_element(*this)
- , scoped_no_eols(*this)
+ , state_(state)
{}
};
+ struct process_element_impl : scoped_action_base {
+ process_element_impl(main_grammar_local& l)
+ : l(l) {}
+
+ bool start()
+ {
+ if (!(l.info.type & l.element.context()) ||
+ qbk_version_n < l.info.qbk_version)
+ return false;
+
+ info_ = l.info;
+
+ if (!l.list_stack.empty() && !l.list_stack.top().root &&
+ info_.type == element_info::block)
+ {
+ // If in a list and the element is a block, end the list.
+ list_item_action list_item(l.state_);
+ list_item();
+ l.clear_stack();
+ }
+ else if (info_.type != element_info::phrase &&
+ info_.type != element_info::maybe_block)
+ {
+ paragraph_action para(l.state_);
+ para();
+ }
+
+ assert(l.state_.values.builder.empty());
+
+ if (!l.state_.source_mode_next.empty() &&
+ info_.type != element_info::maybe_block)
+ {
+ l.state_.source_mode.swap(saved_source_mode_);
+ l.state_.source_mode = l.state_.source_mode_next.get_quickbook();
+ l.state_.source_mode_next = value();
+ }
+
+ return true;
+ }
+
+ template <typename ResultT, typename ScannerT>
+ bool result(ResultT result, ScannerT const& scan)
+ {
+ if (result || info_.type & element_info::in_phrase)
+ return result;
+
+ error_action error(l.state_);
+ error(scan.first, scan.first);
+ return true;
+ }
+
+ void success(parse_iterator, parse_iterator) { l.element_type = info_.type; }
+ void failure() { l.element_type = element_info::nothing; }
+
+ void cleanup() {
+ if (!saved_source_mode_.empty())
+ l.state_.source_mode.swap(saved_source_mode_);
+ }
+
+ main_grammar_local& l;
+ element_info info_;
+ std::string saved_source_mode_;
+ };
+
+ struct set_no_eols_scoped : scoped_action_base
+ {
+ set_no_eols_scoped(main_grammar_local& l)
+ : l(l) {}
+
+ bool start() {
+ saved_no_eols = l.no_eols;
+ l.no_eols = false;
+
+ return true;
+ }
+
+ void cleanup() {
+ l.no_eols = saved_no_eols;
+ }
+
+ main_grammar_local& l;
+ bool saved_no_eols;
+ };
+
+ struct in_list_impl {
+ main_grammar_local& l;
+
+ in_list_impl(main_grammar_local& l) :
+ l(l) {}
+
+ bool operator()() const {
+ return !l.list_stack.top().root;
+ }
+ };
+
////////////////////////////////////////////////////////////////////////////
// Local grammar
void quickbook_grammar::impl::init_main()
{
main_grammar_local& local = cleanup_.add(
- new main_grammar_local(actions));
+ new main_grammar_local(state));
+
+ // Global Actions
+ element_action element(state);
+ paragraph_action paragraph(state);
+ list_item_action list_item(state);
+
+ phrase_end_action end_phrase(state);
+ raw_char_action raw_char(state.phrase);
+ plain_char_action plain_char(state.phrase, state);
+ escape_unicode_action escape_unicode(state.phrase, state);
+
+ simple_phrase_action simple_markup(state.phrase, state);
+
+ break_action break_(state.phrase, state);
+ do_macro_action do_macro(state.phrase, state);
+
+ error_action error(state);
+ element_id_warning_action element_id_warning(state);
+
+ scoped_parser<to_value_scoped_action> to_value(state);
+
+ // Local Actions
+ scoped_parser<process_element_impl> process_element(local);
+ scoped_parser<set_no_eols_scoped> scoped_no_eols(local);
+ in_list_impl in_list(local);
+ member_action<main_grammar_local> check_indentation(local,
+ &main_grammar_local::check_indentation_impl);
+ member_action<main_grammar_local> check_code_block(local,
+ &main_grammar_local::check_code_block_impl);
+ member_action<main_grammar_local> start_blocks(local,
+ &main_grammar_local::start_blocks_impl);
+ member_action<main_grammar_local> end_blocks(local,
+ &main_grammar_local::end_blocks_impl);
// phrase/phrase_start is used for an entirely self-contained
// phrase. For example, any remaining anchors are written out
// at the end instead of being saved for any following content.
phrase_start =
- inline_phrase [actions.phrase_end]
+ inline_phrase [end_phrase]
;
// nested_phrase is used for a phrase nested inside square
// brackets.
nested_phrase =
- actions.values.save()
+ state.values.save()
[ *( ~cl::eps_p(']')
>> local.common(element_info::in_phrase)
)
@@ -272,7 +347,7 @@ namespace quickbook
// paragraph_phrase is like a nested_phrase but is also terminated
// by a paragraph end.
paragraph_phrase =
- actions.values.save()
+ state.values.save()
[ *( ~cl::eps_p(phrase_end)
>> local.common(element_info::in_phrase)
)
@@ -282,7 +357,7 @@ namespace quickbook
// extended_phrase is like a paragraph_phrase but allows some block
// elements.
extended_phrase =
- actions.values.save()
+ state.values.save()
[ *( ~cl::eps_p(phrase_end)
>> local.common(element_info::in_conditional)
)
@@ -294,13 +369,13 @@ namespace quickbook
// is expanding a template, which is parsed separately but
// is part of the paragraph that contains it.
inline_phrase =
- actions.values.save()
+ state.values.save()
[ *local.common(element_info::in_phrase)
]
;
table_title_phrase =
- actions.values.save()
+ state.values.save()
[ *( ~cl::eps_p(space >> (']' | '[' >> space >> '['))
>> local.common(element_info::in_phrase)
)
@@ -308,15 +383,15 @@ namespace quickbook
;
inside_preformatted =
- local.scoped_no_eols()
+ scoped_no_eols()
[ paragraph_phrase
]
;
// Top level blocks
block_start =
- (*eol) [local.start_blocks]
- >> (*local.top_level) [local.end_blocks]
+ (*eol) [start_blocks]
+ >> (*local.top_level) [end_blocks]
;
local.top_level =
@@ -337,7 +412,7 @@ namespace quickbook
( *cl::blank_p
>> !( (cl::ch_p('*') | '#')
>> *cl::blank_p)
- ) [local.check_indentation]
+ ) [check_indentation]
;
local.paragraph =
@@ -346,7 +421,7 @@ namespace quickbook
>> *( cl::eps_p(local.paragraph.still_in_block)
>> local.paragraph_item(element_info::only_block)
)
- >> cl::eps_p [actions.paragraph]
+ >> cl::eps_p [paragraph]
;
local.paragraph_item =
@@ -361,9 +436,13 @@ namespace quickbook
>> (cl::ch_p('*') | '#')
>> (*cl::blank_p) [local.list.still_in_block = true]
>> *( cl::eps_p(local.list.still_in_block)
- >> local.list_item(element_info::only_block)
+ >> ( qbk_ver(106u) >> local.list_item(element_info::only_block)
+ | qbk_ver(0, 106u) >> local.list_item(element_info::only_list_block)
+ )
)
- >> cl::eps_p [actions.list_item]
+ // TODO: This is sometimes called in the wrong place. Currently
+ // harmless.
+ >> cl::eps_p [list_item]
;
local.list_item =
@@ -379,7 +458,7 @@ namespace quickbook
( *cl::blank_p
>> ( cl::eol_p
| cl::end_p
- | cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#')
+ | cl::eps_p(in_list) >> (cl::ch_p('*') | '#')
)
)
>> *eol
@@ -387,25 +466,25 @@ namespace quickbook
// Blocks contains within an element, e.g. a table cell or a footnote.
inside_paragraph =
- actions.values.save()
- [ *( local.paragraph_separator [actions.paragraph]
+ state.values.save()
+ [ *( local.paragraph_separator [paragraph]
>> *eol
| ~cl::eps_p(']')
>> local.common(element_info::in_nested_block)
)
- ] [actions.paragraph]
+ ] [paragraph]
;
local.hr =
cl::str_p("----")
- >> actions.values.list(block_tags::hr)
- [ ( qbk_since(106u)
+ >> state.values.list(block_tags::hr)
+ [ ( qbk_ver(106u)
>> *(line_comment | (cl::anychar_p - (cl::eol_p | '[' | ']')))
- | qbk_before(106u)
+ | qbk_ver(0, 106u)
>> *(line_comment | (cl::anychar_p - (cl::eol_p | "[/")))
)
>> *eol
- ] [actions.element]
+ ] [element]
;
local.element
@@ -415,27 +494,28 @@ namespace quickbook
| elements [ph::var(local.info) = ph::arg1]
>> (cl::eps_p - (cl::alnum_p | '_'))
)
- >> local.process_element()
- [ actions.values.list(ph::var(local.info.tag))
+ >> process_element()
+ [ state.values.list(ph::var(local.info.tag))
[ cl::lazy_p(*ph::var(local.info.rule))
>> space
>> ']'
- ] [actions.element]
+ ] [element]
]
;
local.code =
- (
- local.code_line
+ state.values.list(code_tags::code_block)
+ [( local.code_line
>> *(*local.blank_line >> local.code_line)
- ) [actions.code]
+ ) [state.values.entry(ph::arg1, ph::arg2)]
+ ] [element]
>> *eol
;
local.code_line =
( *cl::blank_p
>> ~cl::eps_p(cl::eol_p)
- ) [local.check_code_block]
+ ) [check_code_block]
>> cl::eps_p(ph::var(local.block_type) == block_types::code)
>> *(cl::anychar_p - cl::eol_p)
>> (cl::eol_p | cl::end_p)
@@ -455,61 +535,61 @@ namespace quickbook
| local.simple_markup
| escape
| comment
- | qbk_since(106u) >> local.square_brackets
- | cl::space_p [actions.raw_char]
- | cl::anychar_p [actions.plain_char]
+ | qbk_ver(106u) >> local.square_brackets
+ | cl::space_p [raw_char]
+ | cl::anychar_p [plain_char]
;
local.square_brackets =
- ( cl::ch_p('[') [actions.plain_char]
+ ( cl::ch_p('[') [plain_char]
>> paragraph_phrase
- >> ( cl::ch_p(']') [actions.plain_char]
- | cl::eps_p [actions.error("Missing close bracket")]
+ >> ( cl::ch_p(']') [plain_char]
+ | cl::eps_p [error("Missing close bracket")]
)
- | cl::ch_p(']') [actions.plain_char]
- >> cl::eps_p [actions.error("Mismatched close bracket")]
+ | cl::ch_p(']') [plain_char]
+ >> cl::eps_p [error("Mismatched close bracket")]
)
;
local.macro =
cl::eps_p
- ( ( actions.macro
+ ( ( state.macro
>> ~cl::eps_p(cl::alpha_p | '_')
// must not be followed by alpha or underscore
)
& macro_identifier // must be a valid macro for the current version
)
- >> actions.macro [actions.do_macro]
+ >> state.macro [do_macro]
;
local.template_ =
( '['
>> space
- >> actions.values.list(template_tags::template_)
- [ !cl::str_p("`") [actions.values.entry(ph::arg1, ph::arg2, template_tags::escape)]
+ >> state.values.list(template_tags::template_)
+ [ !cl::str_p("`") [state.values.entry(ph::arg1, ph::arg2, template_tags::escape)]
>> ( cl::eps_p(cl::punct_p)
- >> actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)]
- | actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)]
+ >> state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)]
+ | state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)]
>> cl::eps_p(hard_space)
)
>> space
>> !local.template_args
>> ']'
]
- ) [actions.element]
+ ) [element]
;
local.template_args =
- qbk_since(105u) >> local.template_args_1_5
- | qbk_before(105u) >> local.template_args_1_4
+ qbk_ver(105u) >> local.template_args_1_5
+ | qbk_ver(0, 105u) >> local.template_args_1_4
;
local.template_args_1_4 = local.template_arg_1_4 >> *(".." >> local.template_arg_1_4);
local.template_arg_1_4 =
( cl::eps_p(*cl::blank_p >> cl::eol_p)
- >> local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)]
- | local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
+ >> local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::block)]
+ | local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
)
;
@@ -525,8 +605,8 @@ namespace quickbook
local.template_arg_1_5 =
( cl::eps_p(*cl::blank_p >> cl::eol_p)
- >> local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)]
- | local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
+ >> local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::block)]
+ | local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)]
)
;
@@ -548,48 +628,55 @@ namespace quickbook
>> "br"
>> space
>> ']'
- ) [actions.break_]
+ ) [break_]
;
local.inline_code =
- '`' >>
- (
+ '`' >> state.values.list(code_tags::inline_code)
+ [(
*(cl::anychar_p -
( '`'
| (cl::eol_p >> *cl::blank_p >> cl::eol_p)
// Make sure that we don't go
) // past a single block
) >> cl::eps_p('`')
- ) [actions.inline_code]
+ ) [state.values.entry(ph::arg1, ph::arg2)]
>> '`'
+ ] [element]
;
local.code_block =
"```"
>> ~cl::eps_p("`")
- >> *(*cl::blank_p >> cl::eol_p)
- >> ( *( "````" >> *cl::ch_p('`')
- | ( cl::anychar_p
- - (*cl::space_p >> "```" >> ~cl::eps_p("`"))
- )
- )
- >> !(*cl::blank_p >> cl::eol_p)
- ) [actions.code_block]
- >> ( *cl::space_p >> "```"
- | cl::eps_p [actions.error("Unfinished code block")]
+ >> ( state.values.list(code_tags::inline_code_block)
+ [ *(*cl::blank_p >> cl::eol_p)
+ >> ( *( "````" >> *cl::ch_p('`')
+ | ( cl::anychar_p
+ - (*cl::space_p >> "```" >> ~cl::eps_p("`"))
+ )
+ )
+ >> !(*cl::blank_p >> cl::eol_p)
+ ) [state.values.entry(ph::arg1, ph::arg2)]
+ >> (*cl::space_p >> "```")
+ ] [element]
+ | cl::eps_p [error("Unfinished code block")]
+ >> *cl::anychar_p
)
| "``"
>> ~cl::eps_p("`")
- >> *(*cl::blank_p >> cl::eol_p)
- >> ( *( "```" >> *cl::ch_p('`')
- | ( cl::anychar_p
- - (*cl::space_p >> "``" >> ~cl::eps_p("`"))
- )
- )
- >> !(*cl::blank_p >> cl::eol_p)
- ) [actions.code_block]
- >> ( *cl::space_p >> "``"
- | cl::eps_p [actions.error("Unfinished code block")]
+ >> ( state.values.list(code_tags::inline_code_block)
+ [ *(*cl::blank_p >> cl::eol_p)
+ >> ( *( "```" >> *cl::ch_p('`')
+ | ( cl::anychar_p
+ - (*cl::space_p >> "``" >> ~cl::eps_p("`"))
+ )
+ )
+ >> !(*cl::blank_p >> cl::eol_p)
+ ) [state.values.entry(ph::arg1, ph::arg2)]
+ >> (*cl::space_p >> "``")
+ ] [element]
+ | cl::eps_p [error("Unfinished code block")]
+ >> *cl::anychar_p
)
;
@@ -606,22 +693,22 @@ namespace quickbook
// by space or punctuation or the
// mark character or a the start.
]
- >> actions.values.save()
+ >> state.values.save()
[
- actions.to_value()
+ to_value()
[
- cl::eps_p((actions.macro & macro_identifier) >> local.simple_markup_end)
- >> actions.macro [actions.do_macro]
+ cl::eps_p((state.macro & macro_identifier) >> local.simple_markup_end)
+ >> state.macro [do_macro]
| ~cl::eps_p(cl::f_ch_p(local.simple_markup.mark))
>> +( ~cl::eps_p
( lookback [~cl::f_ch_p(local.simple_markup.mark)]
>> local.simple_markup_end
)
- >> cl::anychar_p [actions.plain_char]
+ >> cl::anychar_p [plain_char]
)
]
>> cl::f_ch_p(local.simple_markup.mark)
- [actions.simple_markup]
+ [simple_markup]
]
;
@@ -643,37 +730,58 @@ namespace quickbook
;
escape =
- cl::str_p("\\n") [actions.break_]
+ cl::str_p("\\n") [break_]
| cl::str_p("\\ ") // ignore an escaped space
- | '\\' >> cl::punct_p [actions.plain_char]
+ | '\\' >> cl::punct_p [plain_char]
| "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")]
- [actions.escape_unicode]
+ [escape_unicode]
| "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")]
- [actions.escape_unicode]
+ [escape_unicode]
| ("'''" >> !eol)
- >> actions.values.save()
- [ (*(cl::anychar_p - "'''")) [actions.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)]
+ >> state.values.save()
+ [ (*(cl::anychar_p - "'''")) [state.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)]
>> ( cl::str_p("'''")
- | cl::eps_p [actions.error("Unclosed boostbook escape.")]
- ) [actions.element]
+ | cl::eps_p [error("Unclosed boostbook escape.")]
+ ) [element]
]
;
raw_escape =
- cl::str_p("\\n") [actions.error("Newlines invalid here.")]
+ cl::str_p("\\n") [error("Newlines invalid here.")]
| cl::str_p("\\ ") // ignore an escaped space
- | '\\' >> cl::punct_p [actions.raw_char]
+ | '\\' >> cl::punct_p [raw_char]
| "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")]
- [actions.escape_unicode]
+ [escape_unicode]
| "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")]
- [actions.escape_unicode]
- | ('\\' >> cl::anychar_p) [actions.error("Invalid escape.")]
- [actions.raw_char]
- | ("'''" >> !eol) [actions.error("Boostbook escape invalid here.")]
+ [escape_unicode]
+ | ('\\' >> cl::anychar_p) [error("Invalid escape.")]
+ [raw_char]
+ | ("'''" >> !eol) [error("Boostbook escape invalid here.")]
>> (*(cl::anychar_p - "'''"))
>> ( cl::str_p("'''")
- | cl::eps_p [actions.error("Unclosed boostbook escape.")]
- ) [actions.element]
+ | cl::eps_p [error("Unclosed boostbook escape.")]
+ ) [element]
+ ;
+
+ attribute_value_1_7 =
+ *( ~cl::eps_p(']' | cl::space_p | comment)
+ >> ( cl::eps_p
+ ( cl::ch_p('[')
+ >> space
+ >> ( cl::eps_p(cl::punct_p)
+ >> elements
+ | elements
+ >> (cl::eps_p - (cl::alnum_p | '_'))
+ )
+ ) [error("Elements not allowed in attribute values.")]
+ >> local.square_brackets
+ | local.template_
+ | cl::eps_p(cl::ch_p('[')) [error("Unmatched template in attribute value.")]
+ >> local.square_brackets
+ | raw_escape
+ | cl::anychar_p [raw_char]
+ )
+ )
;
//
@@ -681,22 +789,22 @@ namespace quickbook
//
command_line =
- actions.values.list(block_tags::macro_definition)
+ state.values.list(block_tags::macro_definition)
[ *cl::space_p
>> local.command_line_macro_identifier
- [actions.values.entry(ph::arg1, ph::arg2)]
+ [state.values.entry(ph::arg1, ph::arg2)]
>> *cl::space_p
>> !( '='
>> *cl::space_p
- >> actions.to_value() [ inline_phrase ]
+ >> to_value() [ inline_phrase ]
>> *cl::space_p
)
>> cl::end_p
- ] [actions.element]
+ ] [element]
;
local.command_line_macro_identifier =
- qbk_since(106u)
+ qbk_ver(106u)
>> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']' | '='))
| +(cl::anychar_p - (cl::space_p | ']' | '='))
;
@@ -745,9 +853,9 @@ namespace quickbook
;
macro_identifier =
- qbk_since(106u)
+ qbk_ver(106u)
>> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']'))
- | qbk_before(106u)
+ | qbk_ver(0, 106u)
>> +(cl::anychar_p - (cl::space_p | ']'))
;
}
@@ -819,8 +927,8 @@ namespace quickbook
else {
while (!list_stack.top().root && new_indent < list_stack.top().indent)
{
- actions_.end_list_item();
- actions_.end_list(list_stack.top().mark);
+ state_.end_list_item();
+ state_.end_list(list_stack.top().mark);
list_stack.pop();
list_indent = list_stack.top().indent;
}
@@ -853,8 +961,8 @@ namespace quickbook
new_indent > list_stack.top().indent);
if (new_indent <= list_stack.top().indent2) {
- actions_.end_list_item();
- actions_.end_list(save.mark);
+ state_.end_list_item();
+ state_.end_list(save.mark);
list_indent = list_stack.top().indent;
}
else {
@@ -889,44 +997,44 @@ namespace quickbook
if (list_stack.top().root || new_indent > list_indent) {
list_stack.push(list_stack_item(mark, new_indent, new_indent2));
- actions_.start_list(mark);
+ state_.start_list(mark);
}
else if (new_indent == list_indent) {
- actions_.end_list_item();
+ state_.end_list_item();
}
else {
// This should never reach root, since the first list
// has indentation 0.
while(!list_stack.top().root && new_indent < list_stack.top().indent)
{
- actions_.end_list_item();
- actions_.end_list(list_stack.top().mark);
+ state_.end_list_item();
+ state_.end_list(list_stack.top().mark);
list_stack.pop();
}
- actions_.end_list_item();
+ state_.end_list_item();
}
list_indent = new_indent;
if (mark != list_stack.top().mark)
{
- detail::outerr(actions_.current_file, first)
+ detail::outerr(state_.current_file, first)
<< "Illegal change of list style.\n";
- detail::outwarn(actions_.current_file, first)
+ detail::outwarn(state_.current_file, first)
<< "Ignoring change of list style." << std::endl;
- ++actions_.error_count;
+ ++state_.error_count;
}
- actions_.start_list_item();
+ state_.start_list_item();
block_type = block_types::list;
}
void main_grammar_local::clear_stack()
{
while (!list_stack.top().root) {
- actions_.end_list_item();
- actions_.end_list(list_stack.top().mark);
+ state_.end_list_item();
+ state_.end_list(list_stack.top().mark);
list_stack.pop();
}
}
diff --git a/tools/quickbook/src/parsers.hpp b/tools/quickbook/src/parsers.hpp
index 19d385de5e..c1c18803a5 100644
--- a/tools/quickbook/src/parsers.hpp
+++ b/tools/quickbook/src/parsers.hpp
@@ -17,6 +17,7 @@
#include <boost/spirit/include/phoenix1_primitives.hpp>
#include <boost/spirit/include/phoenix1_tuples.hpp>
#include <boost/spirit/include/phoenix1_binders.hpp>
+#include "fwd.hpp"
namespace quickbook {
namespace cl = boost::spirit::classic;
@@ -252,6 +253,48 @@ namespace quickbook {
};
lookback_gen const lookback = lookback_gen();
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // UTF-8 code point
+ //
+ // Very crude, it doesn't check that the code point is in any way valid.
+ // Just looks for the beginning of the next character. This is just for
+ // implementing some crude fixes, rather than full unicode support. I'm
+ // sure experts would be appalled.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+ struct u8_codepoint_parser : public cl::parser<u8_codepoint_parser>
+ {
+ typedef u8_codepoint_parser self_t;
+
+ template <typename Scanner>
+ struct result
+ {
+ typedef cl::match<> type;
+ };
+
+ template <typename Scanner>
+ typename result<Scanner>::type parse(Scanner const& scan) const
+ {
+ typedef typename Scanner::iterator_t iterator_t;
+
+ if (scan.at_end()) return scan.no_match();
+
+ iterator_t save(scan.first);
+
+ do {
+ ++scan.first;
+ } while (!scan.at_end() &&
+ ((unsigned char) *scan.first & 0xc0) == 0x80);
+
+ return scan.create_match(scan.first.base() - save.base(),
+ cl::nil_t(), save, scan.first);
+ }
+ };
+
+ u8_codepoint_parser const u8_codepoint_p = u8_codepoint_parser();
}
#endif // BOOST_QUICKBOOK_SCOPED_BLOCK_HPP
diff --git a/tools/quickbook/src/phrase_element_grammar.cpp b/tools/quickbook/src/phrase_element_grammar.cpp
index 7a4e3c0a09..b287d63621 100644
--- a/tools/quickbook/src/phrase_element_grammar.cpp
+++ b/tools/quickbook/src/phrase_element_grammar.cpp
@@ -9,7 +9,8 @@
=============================================================================*/
#include "grammar_impl.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "utils.hpp"
#include "phrase_tags.hpp"
#include <boost/spirit/include/classic_core.hpp>
@@ -27,7 +28,7 @@ namespace quickbook
{
cl::rule<scanner>
image, anchor, link, empty, cond_phrase, inner_phrase,
- role
+ role, source_mode
;
};
@@ -36,15 +37,19 @@ namespace quickbook
phrase_element_grammar_local& local = cleanup_.add(
new phrase_element_grammar_local);
+ error_action error(state);
+ raw_char_action raw_char(state.phrase);
+ scoped_parser<cond_phrase_push> scoped_cond_phrase(state);
+ scoped_parser<to_value_scoped_action> to_value(state);
+
elements.add
("?", element_info(element_info::phrase, &local.cond_phrase))
;
local.cond_phrase =
blank
- >> macro_identifier [actions.values.entry(ph::arg1, ph::arg2)]
- >> actions.scoped_cond_phrase()
- [extended_phrase]
+ >> macro_identifier [state.values.entry(ph::arg1, ph::arg2)]
+ >> scoped_cond_phrase() [extended_phrase]
;
elements.add
@@ -54,37 +59,37 @@ namespace quickbook
// Note that the attribute values here are encoded in plain text not
// boostbook.
local.image =
- qbk_since(105u)
+ qbk_ver(105u)
>> blank
- >> ( qbk_before(106u)
+ >> ( qbk_ver(0, 106u)
>> (+(
*cl::space_p
>> +(cl::anychar_p - (cl::space_p | phrase_end | '['))
- )) [actions.values.entry(ph::arg1, ph::arg2)]
- | qbk_since(106u)
- >> actions.to_value()
+ )) [state.values.entry(ph::arg1, ph::arg2)]
+ | qbk_ver(106u)
+ >> to_value()
[ +( raw_escape
| (+cl::space_p >> ~cl::eps_p(phrase_end | '['))
- [actions.raw_char]
+ [raw_char]
| (cl::anychar_p - (cl::space_p | phrase_end | '['))
- [actions.raw_char]
+ [raw_char]
)
]
)
>> hard_space
- >> *actions.values.list()
+ >> *state.values.list()
[ '['
>> (*(cl::alnum_p | '_'))
- [actions.values.entry(ph::arg1, ph::arg2)]
+ [state.values.entry(ph::arg1, ph::arg2)]
>> space
- >> ( qbk_before(106u)
+ >> ( qbk_ver(0, 106u)
>> (*(cl::anychar_p - (phrase_end | '[')))
- [actions.values.entry(ph::arg1, ph::arg2)]
- | qbk_since(106u)
- >> actions.to_value()
+ [state.values.entry(ph::arg1, ph::arg2)]
+ | qbk_ver(106u)
+ >> to_value()
[ *( raw_escape
| (cl::anychar_p - (phrase_end | '['))
- [actions.raw_char]
+ [raw_char]
)
]
)
@@ -92,9 +97,9 @@ namespace quickbook
>> space
]
>> cl::eps_p(']')
- | qbk_before(105u)
+ | qbk_ver(0, 105u)
>> blank
- >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)]
+ >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)]
>> cl::eps_p(']')
;
@@ -113,16 +118,21 @@ namespace quickbook
local.link =
space
- >> ( qbk_before(106u)
+ >> ( qbk_ver(0, 106u)
>> (*(cl::anychar_p - (']' | space)))
- [actions.values.entry(ph::arg1, ph::arg2)]
- | qbk_since(106u)
- >> actions.to_value()
+ [state.values.entry(ph::arg1, ph::arg2)]
+ | qbk_ver(106u, 107u)
+ >> to_value()
[ *( raw_escape
- | (cl::anychar_p - (']' | space))
- [actions.raw_char]
+ | (cl::anychar_p - (cl::ch_p('[') | ']' | space))
+ [raw_char]
)
]
+ >> !( ~cl::eps_p(comment)
+ >> cl::eps_p('[') [error("Open bracket in link value.")]
+ )
+ | qbk_ver(107u)
+ >> to_value() [attribute_value_1_7]
)
>> hard_space
>> local.inner_phrase
@@ -134,13 +144,13 @@ namespace quickbook
local.anchor =
blank
- >> ( qbk_before(106u)
- >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)]
- | qbk_since(106u)
- >> actions.to_value()
+ >> ( qbk_ver(0, 106u)
+ >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)]
+ | qbk_ver(106u)
+ >> to_value()
[ *( raw_escape
| (cl::anychar_p - phrase_end)
- [actions.raw_char]
+ [raw_char]
)
]
)
@@ -157,6 +167,15 @@ namespace quickbook
("footnote", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::footnote))
;
+ elements.add("!", element_info(element_info::maybe_block, &local.source_mode, code_tags::next_source_mode, 107u))
+ ;
+
+ local.source_mode =
+ ( cl::str_p("c++")
+ | "python"
+ | "teletype"
+ ) [state.values.entry(ph::arg1, ph::arg2)];
+
elements.add
("c++", element_info(element_info::phrase, &local.empty, source_mode_tags::cpp))
("python", element_info(element_info::phrase, &local.empty, source_mode_tags::python))
@@ -169,7 +188,7 @@ namespace quickbook
local.role
= space
- >> (+(cl::alnum_p | '_')) [actions.values.entry(ph::arg1, ph::arg2)]
+ >> (+(cl::alnum_p | '_')) [state.values.entry(ph::arg1, ph::arg2)]
>> hard_space
>> local.inner_phrase
;
@@ -178,7 +197,7 @@ namespace quickbook
local.inner_phrase =
blank
- >> actions.to_value() [ paragraph_phrase ]
+ >> to_value() [ paragraph_phrase ]
;
}
}
diff --git a/tools/quickbook/src/phrase_tags.hpp b/tools/quickbook/src/phrase_tags.hpp
index bf9b754b6c..f4bba91653 100644
--- a/tools/quickbook/src/phrase_tags.hpp
+++ b/tools/quickbook/src/phrase_tags.hpp
@@ -30,6 +30,13 @@ namespace quickbook
((python)("python"))
((teletype)("teletype"))
)
+
+ QUICKBOOK_VALUE_TAGS(code_tags, 0x560,
+ (code_block)
+ (inline_code)
+ (inline_code_block)
+ (next_source_mode)
+ )
}
#endif
diff --git a/tools/quickbook/src/quickbook.cpp b/tools/quickbook/src/quickbook.cpp
index fc197b58c7..5a359ed3e1 100644
--- a/tools/quickbook/src/quickbook.cpp
+++ b/tools/quickbook/src/quickbook.cpp
@@ -9,19 +9,21 @@
=============================================================================*/
#include "grammar.hpp"
#include "quickbook.hpp"
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
#include "post_process.hpp"
#include "utils.hpp"
#include "files.hpp"
#include "input_path.hpp"
#include "id_manager.hpp"
#include <boost/program_options.hpp>
-#include <boost/filesystem/v3/path.hpp>
-#include <boost/filesystem/v3/operations.hpp>
-#include <boost/filesystem/v3/fstream.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/ref.hpp>
#include <boost/version.hpp>
+#include <boost/foreach.hpp>
#include <stdexcept>
#include <vector>
@@ -36,7 +38,7 @@
#pragma warning(disable:4355)
#endif
-#define QUICKBOOK_VERSION "Quickbook Version 1.5.7"
+#define QUICKBOOK_VERSION "Quickbook Version 1.5.8"
namespace quickbook
{
@@ -52,7 +54,7 @@ namespace quickbook
std::vector<std::string> preset_defines;
fs::path image_location;
- static void set_macros(actions& actor)
+ static void set_macros(quickbook::state& state)
{
for(std::vector<std::string>::const_iterator
it = preset_defines.begin(),
@@ -63,15 +65,15 @@ namespace quickbook
parse_iterator last(it->end());
cl::parse_info<parse_iterator> info =
- cl::parse(first, last, actor.grammar().command_line_macro);
+ cl::parse(first, last, state.grammar().command_line_macro);
if (!info.full) {
detail::outerr()
<< "Error parsing command line definition: '"
- << detail::utf8(*it)
+ << *it
<< "'"
<< std::endl;
- ++actor.error_count;
+ ++state.error_count;
}
}
}
@@ -81,29 +83,29 @@ namespace quickbook
// Parse a file
//
///////////////////////////////////////////////////////////////////////////
- void parse_file(actions& actor, value include_doc_id, bool nested_file)
+ void parse_file(quickbook::state& state, value include_doc_id, bool nested_file)
{
- parse_iterator first(actor.current_file->source.begin());
- parse_iterator last(actor.current_file->source.end());
+ parse_iterator first(state.current_file->source.begin());
+ parse_iterator last(state.current_file->source.end());
- cl::parse_info<parse_iterator> info = cl::parse(first, last, actor.grammar().doc_info);
+ cl::parse_info<parse_iterator> info = cl::parse(first, last, state.grammar().doc_info);
assert(info.hit);
- if (!actor.error_count)
+ if (!state.error_count)
{
parse_iterator pos = info.stop;
- std::string doc_type = pre(actor, pos, include_doc_id, nested_file);
+ std::string doc_type = pre(state, pos, include_doc_id, nested_file);
- info = cl::parse(info.hit ? info.stop : first, last, actor.grammar().block);
+ info = cl::parse(info.hit ? info.stop : first, last, state.grammar().block);
- post(actor, doc_type);
+ post(state, doc_type);
if (!info.full)
{
- file_position const& pos = actor.current_file->position_of(info.stop.base());
- detail::outerr(actor.current_file->path, pos.line)
+ file_position const& pos = state.current_file->position_of(info.stop.base());
+ detail::outerr(state.current_file->path, pos.line)
<< "Syntax Error near column " << pos.column << ".\n";
- ++actor.error_count;
+ ++state.error_count;
}
}
}
@@ -112,6 +114,8 @@ namespace quickbook
parse_document(
fs::path const& filein_
, fs::path const& fileout_
+ , fs::path const& deps_out_
+ , fs::path const& locations_out_
, fs::path const& xinclude_base_
, int indent
, int linewidth
@@ -123,28 +127,52 @@ namespace quickbook
int result = 0;
try {
- actions actor(filein_, xinclude_base_, buffer, ids);
- set_macros(actor);
+ quickbook::state state(filein_, xinclude_base_, buffer, ids);
+ set_macros(state);
- if (actor.error_count == 0) {
- actor.current_file = load(filein_); // Throws load_error
+ if (state.error_count == 0) {
+ state.add_dependency(filein_);
+ state.current_file = load(filein_); // Throws load_error
- parse_file(actor);
+ parse_file(state);
- if(actor.error_count) {
+ if(state.error_count) {
detail::outerr()
- << "Error count: " << actor.error_count << ".\n";
+ << "Error count: " << state.error_count << ".\n";
}
}
- result = actor.error_count ? 1 : 0;
+ result = state.error_count ? 1 : 0;
+
+ if (!deps_out_.empty())
+ {
+ fs::ofstream out(deps_out_);
+ BOOST_FOREACH(quickbook::state::dependency_list::value_type
+ const& d, state.dependencies)
+ {
+ if (d.second) {
+ out << detail::path_to_generic(d.first) << std::endl;
+ }
+ }
+ }
+
+ if (!locations_out_.empty())
+ {
+ fs::ofstream out(locations_out_);
+ BOOST_FOREACH(quickbook::state::dependency_list::value_type
+ const& d, state.dependencies)
+ {
+ out << (d.second ? "+ " : "- ")
+ << detail::path_to_generic(d.first) << std::endl;
+ }
+ }
}
catch (load_error& e) {
- detail::outerr(filein_) << detail::utf8(e.what()) << std::endl;
+ detail::outerr(filein_) << e.what() << std::endl;
result = 1;
}
- if (result == 0)
+ if (!fileout_.empty() && result == 0)
{
std::string stage2 = ids.replace_placeholders(buffer.str());
@@ -244,6 +272,7 @@ main(int argc, char* argv[])
("linewidth", PO_VALUE<int>(), "line width")
("input-file", PO_VALUE<input_string>(), "input file")
("output-file", PO_VALUE<input_string>(), "output file")
+ ("output-deps", PO_VALUE<input_string>(), "output dependency file")
("debug", "debug mode (for developers)")
("ms-errors", "use Microsoft Visual Studio style error & warn message format")
("include-path,I", PO_VALUE< std::vector<input_string> >(), "include path")
@@ -258,6 +287,10 @@ main(int argc, char* argv[])
("xinclude-base", PO_VALUE<input_string>(),
"Generate xincludes as if generating for this target "
"directory.")
+ ("output-checked-locations", PO_VALUE<input_string>(),
+ "Writes a file listing all the file locations that were "
+ "checked, starting with '+' if they were found, or '-' "
+ "if they weren't.")
;
all.add(desc).add(hidden);
@@ -306,8 +339,7 @@ main(int argc, char* argv[])
std::ostringstream description_text;
description_text << desc;
- quickbook::detail::out()
- << quickbook::detail::utf8(description_text.str()) << "\n";
+ quickbook::detail::out() << description_text.str() << "\n";
return 0;
}
@@ -320,7 +352,7 @@ main(int argc, char* argv[])
quickbook::detail::out()
<< QUICKBOOK_VERSION
<< " (Boost "
- << quickbook::detail::utf8(boost_version)
+ << boost_version
<< ")"
<< std::endl;
return 0;
@@ -388,18 +420,36 @@ main(int argc, char* argv[])
fs::path filein = quickbook::detail::input_to_path(
vm["input-file"].as<input_string>());
fs::path fileout;
+ fs::path deps_out;
+ fs::path locations_out;
+
+ bool default_output = true;
+
+ if (vm.count("output-deps"))
+ {
+ deps_out = quickbook::detail::input_to_path(
+ vm["output-deps"].as<input_string>());
+ default_output = false;
+ }
+
+ if (vm.count("output-checked-locations"))
+ {
+ locations_out = quickbook::detail::input_to_path(
+ vm["output-checked-locations"].as<input_string>());
+ default_output = false;
+ }
if (vm.count("output-file"))
{
fileout = quickbook::detail::input_to_path(
vm["output-file"].as<input_string>());
}
- else
+ else if (default_output)
{
fileout = filein;
fileout.replace_extension(".xml");
}
-
+
fs::path xinclude_base;
if (vm.count("xinclude-base"))
{
@@ -432,12 +482,16 @@ main(int argc, char* argv[])
quickbook::image_location = filein.parent_path() / "html";
}
- quickbook::detail::out() << "Generating Output File: "
- << quickbook::detail::path_to_stream(fileout)
- << std::endl;
+ if (!fileout.empty()) {
+ quickbook::detail::out() << "Generating Output File: "
+ << fileout
+ << std::endl;
+ }
if (!error_count)
- error_count += quickbook::parse_document(filein, fileout, xinclude_base, indent, linewidth, pretty_print);
+ error_count += quickbook::parse_document(
+ filein, fileout, deps_out, locations_out,
+ xinclude_base, indent, linewidth, pretty_print);
if (expect_errors)
{
@@ -455,14 +509,14 @@ main(int argc, char* argv[])
description_text << desc;
quickbook::detail::outerr() << "No filename given\n\n"
- << quickbook::detail::utf8(description_text.str()) << std::endl;
+ << description_text.str() << std::endl;
return 1;
}
}
catch(std::exception& e)
{
- quickbook::detail::outerr() << quickbook::detail::utf8(e.what()) << "\n";
+ quickbook::detail::outerr() << e.what() << "\n";
return 1;
}
diff --git a/tools/quickbook/src/quickbook.hpp b/tools/quickbook/src/quickbook.hpp
index 265bc7ee53..27d07a4125 100644
--- a/tools/quickbook/src/quickbook.hpp
+++ b/tools/quickbook/src/quickbook.hpp
@@ -15,7 +15,7 @@
#include <time.h>
#include <vector>
#include <string>
-#include <boost/filesystem/v3/path.hpp>
+#include <boost/filesystem/path.hpp>
#include "fwd.hpp"
#include "values.hpp"
@@ -31,7 +31,7 @@ namespace quickbook
extern std::vector<std::string> preset_defines;
extern fs::path image_location;
- void parse_file(actions& actor,
+ void parse_file(quickbook::state& state,
value include_doc_id = value(),
bool nested_file = false);
// Some initialisation methods
diff --git a/tools/quickbook/src/state.cpp b/tools/quickbook/src/state.cpp
new file mode 100644
index 0000000000..d16200d626
--- /dev/null
+++ b/tools/quickbook/src/state.cpp
@@ -0,0 +1,160 @@
+/*=============================================================================
+ Copyright (c) 2002 2004 2006 Joel de Guzman
+ Copyright (c) 2004 Eric Niebler
+ Copyright (c) 2005 Thomas Guest
+ http://spirit.sourceforge.net/
+
+ Use, modification and distribution is subject to the Boost Software
+ License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#include "state.hpp"
+#include "state_save.hpp"
+#include "quickbook.hpp"
+#include "grammar.hpp"
+#include "input_path.hpp"
+#include <boost/filesystem/operations.hpp>
+
+#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
+#pragma warning(disable:4355)
+#endif
+
+namespace quickbook
+{
+ char const* quickbook_get_date = "__quickbook_get_date__";
+ char const* quickbook_get_time = "__quickbook_get_time__";
+
+ unsigned qbk_version_n = 0; // qbk_major_version * 100 + qbk_minor_version
+
+ state::state(fs::path const& filein_, fs::path const& xinclude_base_,
+ string_stream& out_, id_manager& ids)
+ : grammar_()
+
+ , xinclude_base(xinclude_base_)
+
+ , templates()
+ , error_count(0)
+ , anchors()
+ , warned_about_breaks(false)
+ , conditional(true)
+ , ids(ids)
+ , callouts()
+ , callout_depth(0)
+
+ , imported(false)
+ , macro()
+ , source_mode("c++")
+ , source_mode_next()
+ , current_file(0)
+ , filename_relative(filein_.filename())
+
+ , template_depth(0)
+ , min_section_level(1)
+
+ , out(out_)
+ , phrase()
+ , values(&current_file)
+ {
+ // add the predefined macros
+ macro.add
+ ("__DATE__", std::string(quickbook_get_date))
+ ("__TIME__", std::string(quickbook_get_time))
+ ("__FILENAME__", detail::path_to_generic(filename_relative))
+ ;
+
+ boost::scoped_ptr<quickbook_grammar> g(
+ new quickbook_grammar(*this));
+ grammar_.swap(g);
+ }
+
+ quickbook_grammar& state::grammar() const {
+ return *grammar_;
+ }
+
+ bool state::add_dependency(fs::path const& f) {
+ fs::path p = fs::absolute(f);
+ bool found = fs::exists(fs::status(p));
+
+ // Pop path sections from path until we find an existing
+ // path, adjusting for any dot path sections.
+ fs::path extra;
+ int parent_count = 0;
+ while (!fs::exists(fs::status(p))) {
+ fs::path name = p.filename();
+ p = p.parent_path();
+ if (name == "..") {
+ ++parent_count;
+ }
+ else if (name == ".") {
+ }
+ else if (parent_count) {
+ --parent_count;
+ }
+ else {
+ extra = name / extra;
+ }
+ }
+
+ // If there are any left over ".." sections, then add them
+ // on to the end of the real path, and trust Boost.Filesystem
+ // to sort them out.
+ while (parent_count) {
+ p = p / "..";
+ --parent_count;
+ }
+
+ p = fs::canonical(p) / extra;
+ dependencies[p] |= found;
+ return found;
+ }
+
+ file_state::file_state(quickbook::state& state, scope_flags scope)
+ : state(state)
+ , scope(scope)
+ , qbk_version(qbk_version_n)
+ , imported(state.imported)
+ , current_file(state.current_file)
+ , filename_relative(state.filename_relative)
+ , xinclude_base(state.xinclude_base)
+ , source_mode(state.source_mode)
+ , macro()
+ {
+ if (scope & scope_macros) macro = state.macro;
+ if (scope & scope_templates) state.templates.push();
+ if (scope & scope_output) {
+ state.out.push();
+ state.phrase.push();
+ }
+ state.values.builder.save();
+ }
+
+ file_state::~file_state()
+ {
+ state.values.builder.restore();
+ boost::swap(qbk_version_n, qbk_version);
+ boost::swap(state.imported, imported);
+ boost::swap(state.current_file, current_file);
+ boost::swap(state.filename_relative, filename_relative);
+ boost::swap(state.xinclude_base, xinclude_base);
+ boost::swap(state.source_mode, source_mode);
+ if (scope & scope_output) {
+ state.out.pop();
+ state.phrase.pop();
+ }
+ if (scope & scope_templates) state.templates.pop();
+ if (scope & scope_macros) state.macro = macro;
+ }
+
+ template_state::template_state(quickbook::state& state)
+ : file_state(state, file_state::scope_all)
+ , template_depth(state.template_depth)
+ , min_section_level(state.min_section_level)
+ {
+ }
+
+ template_state::~template_state()
+ {
+ boost::swap(state.template_depth, template_depth);
+ boost::swap(state.min_section_level, min_section_level);
+ }
+}
diff --git a/tools/quickbook/src/actions_class.hpp b/tools/quickbook/src/state.hpp
index 979c3ccf67..b750904588 100644
--- a/tools/quickbook/src/actions_class.hpp
+++ b/tools/quickbook/src/state.hpp
@@ -10,20 +10,22 @@
#if !defined(BOOST_SPIRIT_ACTIONS_CLASS_HPP)
#define BOOST_SPIRIT_ACTIONS_CLASS_HPP
+#include <map>
#include <boost/scoped_ptr.hpp>
-#include "actions.hpp"
#include "parsers.hpp"
#include "values_parse.hpp"
#include "collector.hpp"
+#include "template_stack.hpp"
+#include "symbols.hpp"
namespace quickbook
{
namespace cl = boost::spirit::classic;
namespace fs = boost::filesystem;
- struct actions
+ struct state
{
- actions(fs::path const& filein_, fs::path const& xinclude_base, string_stream& out_,
+ state(fs::path const& filein_, fs::path const& xinclude_base, string_stream& out_,
id_manager&);
private:
@@ -35,9 +37,10 @@ namespace quickbook
///////////////////////////////////////////////////////////////////////////
typedef std::vector<std::string> string_list;
+ typedef std::map<fs::path, bool> dependency_list;
static int const max_template_depth = 100;
-
+
// global state
fs::path xinclude_base;
template_stack templates;
@@ -46,12 +49,16 @@ namespace quickbook
bool warned_about_breaks;
bool conditional;
id_manager& ids;
+ value_builder callouts; // callouts are global as
+ int callout_depth; // they don't nest.
+ dependency_list dependencies;
// state saved for files and templates.
bool imported;
string_symbols macro;
std::string source_mode;
- file_ptr current_file;
+ value source_mode_next;
+ file_ptr current_file;
fs::path filename_relative; // for the __FILENAME__ macro.
// (relative to the original file
// or include path).
@@ -71,37 +78,23 @@ namespace quickbook
// actions
///////////////////////////////////////////////////////////////////////////
+ // Call this before loading any file so that it will be included in the
+ // list of dependencies. Returns true if file exists.
+ bool add_dependency(fs::path const&);
+
void start_list(char mark);
void end_list(char mark);
void start_list_item();
void end_list_item();
- scoped_parser<to_value_scoped_action>
- to_value;
- scoped_parser<cond_phrase_push>
- scoped_cond_phrase;
-
- element_action element;
- error_action error;
-
- code_action code;
- code_action code_block;
- code_action inline_code;
- paragraph_action paragraph;
- list_item_action list_item;
- phrase_end_action phrase_end;
- raw_char_action raw_char;
- plain_char_action plain_char;
- escape_unicode_action escape_unicode;
-
- simple_phrase_action simple_markup;
-
- break_action break_;
- do_macro_action do_macro;
-
- element_id_warning_action element_id_warning;
+ void start_callouts();
+ std::string add_callout(value);
+ std::string end_callouts();
};
+
+ extern unsigned qbk_version_n; // qbk_major_version * 100 + qbk_minor_version
+ extern char const* quickbook_get_date;
+ extern char const* quickbook_get_time;
}
#endif // BOOST_SPIRIT_ACTIONS_CLASS_HPP
-
diff --git a/tools/quickbook/src/actions_state.hpp b/tools/quickbook/src/state_save.hpp
index aefa7f99da..f8b53e7c8e 100644
--- a/tools/quickbook/src/actions_state.hpp
+++ b/tools/quickbook/src/state_save.hpp
@@ -10,13 +10,13 @@
#if !defined(BOOST_SPIRIT_ACTIONS_STATE_HPP)
#define BOOST_SPIRIT_ACTIONS_STATE_HPP
-#include "actions_class.hpp"
+#include "state.hpp"
namespace quickbook
{
// State savers
//
- // Defined in actions_class.cpp
+ // Defined in state.cpp
struct file_state
{
@@ -29,10 +29,10 @@ namespace quickbook
scope_all = scope_callables + scope_output
};
- explicit file_state(actions&, scope_flags);
+ explicit file_state(quickbook::state&, scope_flags);
~file_state();
- quickbook::actions& a;
+ quickbook::state& state;
scope_flags scope;
unsigned qbk_version;
bool imported;
@@ -49,7 +49,7 @@ namespace quickbook
struct template_state : file_state
{
- explicit template_state(actions&);
+ explicit template_state(quickbook::state&);
~template_state();
int template_depth;
diff --git a/tools/quickbook/src/string_ref.cpp b/tools/quickbook/src/string_ref.cpp
index b4775576da..6c33df1260 100644
--- a/tools/quickbook/src/string_ref.cpp
+++ b/tools/quickbook/src/string_ref.cpp
@@ -9,10 +9,17 @@
#include "string_ref.hpp"
#include <boost/range/algorithm/equal.hpp>
#include <boost/range/algorithm/lexicographical_compare.hpp>
+#include <boost/utility/swap.hpp>
#include <ostream>
namespace quickbook
{
+ void string_ref::swap(string_ref& x)
+ {
+ boost::swap(begin_, x.begin_);
+ boost::swap(end_, x.end_);
+ }
+
bool operator==(string_ref const& x, string_ref const& y)
{
return boost::equal(x, y);
diff --git a/tools/quickbook/src/string_ref.hpp b/tools/quickbook/src/string_ref.hpp
index b712006790..ffb95bf71d 100644
--- a/tools/quickbook/src/string_ref.hpp
+++ b/tools/quickbook/src/string_ref.hpp
@@ -37,6 +37,12 @@ namespace quickbook
explicit string_ref(std::string const& x)
: begin_(x.begin()), end_(x.end()) {}
+ void swap(string_ref&);
+
+ void clear() {
+ begin_ = end_ = iterator();
+ }
+
operator std::string() const {
return std::string(begin_, end_);
}
@@ -73,6 +79,11 @@ namespace quickbook
{
return x > string_ref(y);
}
+
+ inline void swap(string_ref& x, string_ref& y)
+ {
+ x.swap(y);
+ }
}
#endif
diff --git a/tools/quickbook/src/syntax_highlight.cpp b/tools/quickbook/src/syntax_highlight.cpp
index 2e790f5bb1..e618c07dd6 100644
--- a/tools/quickbook/src/syntax_highlight.cpp
+++ b/tools/quickbook/src/syntax_highlight.cpp
@@ -14,7 +14,9 @@
#include <boost/spirit/include/classic_loops.hpp>
#include "grammar.hpp"
#include "grammar_impl.hpp" // Just for context stuff. Should move?
-#include "actions_class.hpp"
+#include "state.hpp"
+#include "actions.hpp"
+#include "utils.hpp"
#include "files.hpp"
#include "input_path.hpp"
@@ -22,102 +24,100 @@ namespace quickbook
{
namespace cl = boost::spirit::classic;
- // quickbook::actions is used in a few places here, as 'escape_actions'.
- // It's named differently to distinguish it from the syntax highlighting
- // actions, declared below.
-
- // Syntax Highlight Actions
-
- struct span
+ template <typename T, typename Value>
+ struct member_action_value
{
- // Decorates c++ code fragments
+ typedef void(T::*member_function)(Value);
- span(char const* name, collector& out)
- : name(name), out(out) {}
+ T& l;
+ member_function mf;
- void operator()(parse_iterator first, parse_iterator last) const;
+ member_action_value(T& l, member_function mf) : l(l), mf(mf) {}
- char const* name;
- collector& out;
+ void operator()(Value v) const {
+ (l.*mf)(v);
+ }
};
- struct span_start
+ template <typename T>
+ struct member_action
{
- span_start(char const* name, collector& out)
- : name(name), out(out) {}
+ typedef void(T::*member_function)(parse_iterator, parse_iterator);
- void operator()(parse_iterator first, parse_iterator last) const;
+ T& l;
+ member_function mf;
- char const* name;
- collector& out;
- };
+ member_action(T& l, member_function mf) : l(l), mf(mf) {}
- struct span_end
- {
- span_end(collector& out)
- : out(out) {}
-
- void operator()(parse_iterator first, parse_iterator last) const;
-
- collector& out;
+ void operator()(parse_iterator first, parse_iterator last) const {
+ (l.*mf)(first, last);
+ }
};
- struct unexpected_char
+ template <typename T, typename Arg1>
+ struct member_action1
{
- // Handles unexpected chars in c++ syntax
+ typedef void(T::*member_function)(parse_iterator, parse_iterator, Arg1);
- unexpected_char(
- collector& out
- , quickbook::actions& escape_actions)
- : out(out)
- , escape_actions(escape_actions) {}
+ T& l;
+ member_function mf;
- void operator()(parse_iterator first, parse_iterator last) const;
-
- collector& out;
- quickbook::actions& escape_actions;
- };
+ member_action1(T& l, member_function mf) : l(l), mf(mf) {}
- struct plain_char
- {
- // Prints a single plain char.
- // Converts '<' to "&lt;"... etc See utils.hpp
+ struct impl
+ {
+ member_action1 a;
+ Arg1 value;
- plain_char(collector& out)
- : out(out) {}
+ impl(member_action1& a, Arg1 value) :
+ a(a), value(value)
+ {}
- void operator()(char ch) const;
- void operator()(parse_iterator first, parse_iterator last) const;
+ void operator()(parse_iterator first, parse_iterator last) const {
+ (a.l.*a.mf)(first, last, value);
+ }
+ };
- collector& out;
+ impl operator()(Arg1 a1) {
+ return impl(*this, a1);
+ }
};
- struct pre_escape_back
- {
- // Escapes back from code to quickbook (Pre)
-
- pre_escape_back(actions& escape_actions)
- : escape_actions(escape_actions) {}
-
- void operator()(parse_iterator first, parse_iterator last) const;
-
- actions& escape_actions;
- };
+ // Syntax Highlight Actions
- struct post_escape_back
+ struct syntax_highlight_actions
{
- // Escapes back from code to quickbook (Post)
-
- post_escape_back(collector& out, actions& escape_actions)
- : out(out), escape_actions(escape_actions) {}
-
- void operator()(parse_iterator first, parse_iterator last) const;
-
- collector& out;
- actions& escape_actions;
+ quickbook::collector out;
+ quickbook::state& state;
+ do_macro_action do_macro_impl;
+
+ // State
+ bool support_callouts;
+ string_ref marked_text;
+
+ syntax_highlight_actions(quickbook::state& state, bool is_block) :
+ out(), state(state),
+ do_macro_impl(out, state),
+ support_callouts(is_block && (qbk_version_n >= 107u ||
+ state.current_file->is_code_snippets)),
+ marked_text()
+ {}
+
+ void span(parse_iterator, parse_iterator, char const*);
+ void span_start(parse_iterator, parse_iterator, char const*);
+ void span_end(parse_iterator, parse_iterator);
+ void unexpected_char(parse_iterator, parse_iterator);
+ void plain_char(parse_iterator, parse_iterator);
+ void pre_escape_back(parse_iterator, parse_iterator);
+ void post_escape_back(parse_iterator, parse_iterator);
+ void do_macro(std::string const&);
+
+ void mark_text(parse_iterator, parse_iterator);
+ void callout(parse_iterator, parse_iterator);
};
- void span::operator()(parse_iterator first, parse_iterator last) const
+ void syntax_highlight_actions::span(parse_iterator first,
+ parse_iterator last, char const* name)
{
out << "<phrase role=\"" << name << "\">";
while (first != last)
@@ -125,27 +125,30 @@ namespace quickbook
out << "</phrase>";
}
- void span_start::operator()(parse_iterator first, parse_iterator last) const
+ void syntax_highlight_actions::span_start(parse_iterator first,
+ parse_iterator last, char const* name)
{
out << "<phrase role=\"" << name << "\">";
while (first != last)
detail::print_char(*first++, out.get());
}
- void span_end::operator()(parse_iterator first, parse_iterator last) const
+ void syntax_highlight_actions::span_end(parse_iterator first,
+ parse_iterator last)
{
while (first != last)
detail::print_char(*first++, out.get());
out << "</phrase>";
}
- void unexpected_char::operator()(parse_iterator first, parse_iterator last) const
+ void syntax_highlight_actions::unexpected_char(parse_iterator first,
+ parse_iterator last)
{
- file_position const pos = escape_actions.current_file->position_of(first.base());
+ file_position const pos = state.current_file->position_of(first.base());
- detail::outwarn(escape_actions.current_file->path, pos.line)
+ detail::outwarn(state.current_file->path, pos.line)
<< "in column:" << pos.column
- << ", unexpected character: " << detail::utf8(first, last)
+ << ", unexpected character: " << std::string(first.base(), last.base())
<< "\n";
// print out an unexpected character
@@ -155,26 +158,42 @@ namespace quickbook
out << "</phrase>";
}
- void plain_char::operator()(char ch) const
+ void syntax_highlight_actions::plain_char(parse_iterator first,
+ parse_iterator last)
{
- detail::print_char(ch, out.get());
+ while (first != last)
+ detail::print_char(*first++, out.get());
}
- void plain_char::operator()(parse_iterator first, parse_iterator last) const
+ void syntax_highlight_actions::pre_escape_back(parse_iterator,
+ parse_iterator)
{
- while (first != last)
- detail::print_char(*first++, out.get());
+ state.phrase.push(); // save the stream
+ }
+
+ void syntax_highlight_actions::post_escape_back(parse_iterator,
+ parse_iterator)
+ {
+ out << state.phrase.str();
+ state.phrase.pop(); // restore the stream
+ }
+
+ void syntax_highlight_actions::do_macro(std::string const& v)
+ {
+ do_macro_impl(v);
}
- void pre_escape_back::operator()(parse_iterator, parse_iterator) const
+ void syntax_highlight_actions::mark_text(parse_iterator first,
+ parse_iterator last)
{
- escape_actions.phrase.push(); // save the stream
+ marked_text = string_ref(first.base(), last.base());
}
- void post_escape_back::operator()(parse_iterator, parse_iterator) const
+ void syntax_highlight_actions::callout(parse_iterator, parse_iterator)
{
- out << escape_actions.phrase.str();
- escape_actions.phrase.pop(); // restore the stream
+ out << state.add_callout(qbk_value(state.current_file,
+ marked_text.begin(), marked_text.end()));
+ marked_text.clear();
}
// Syntax
@@ -225,45 +244,63 @@ namespace quickbook
}
// Grammar for C++ highlighting
- struct cpp_highlight
- : public cl::grammar<cpp_highlight>
+ struct cpp_highlight : public cl::grammar<cpp_highlight>
{
- cpp_highlight(collector& out, actions& escape_actions)
- : out(out), escape_actions(escape_actions) {}
+ cpp_highlight(syntax_highlight_actions& actions)
+ : actions(actions) {}
template <typename Scanner>
struct definition
{
definition(cpp_highlight const& self)
- : g(self.escape_actions.grammar())
+ : g(self.actions.state.grammar())
{
+ member_action1<syntax_highlight_actions, char const*>
+ span(self.actions, &syntax_highlight_actions::span),
+ span_start(self.actions, &syntax_highlight_actions::span_start);
+ member_action<syntax_highlight_actions>
+ span_end(self.actions, &syntax_highlight_actions::span_end),
+ unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char),
+ plain_char(self.actions, &syntax_highlight_actions::plain_char),
+ pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back),
+ post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back),
+ mark_text(self.actions, &syntax_highlight_actions::mark_text),
+ callout(self.actions, &syntax_highlight_actions::callout);
+ member_action_value<syntax_highlight_actions, std::string const&>
+ do_macro(self.actions, &syntax_highlight_actions::do_macro);
+ error_action error(self.actions.state);
+
program
=
- *( (+cl::space_p) [plain_char(self.out)]
+ *( (+cl::space_p) [plain_char]
| macro
| escape
- | preprocessor [span("preprocessor", self.out)]
+ | preprocessor [span("preprocessor")]
+ | cl::eps_p(ph::var(self.actions.support_callouts))
+ >> ( line_callout [callout]
+ | inline_callout [callout]
+ )
| comment
- | keyword [span("keyword", self.out)]
- | identifier [span("identifier", self.out)]
- | special [span("special", self.out)]
- | string_ [span("string", self.out)]
- | char_ [span("char", self.out)]
- | number [span("number", self.out)]
- | cl::repeat_p(1)[cl::anychar_p]
- [unexpected_char(self.out, self.escape_actions)]
+ | keyword [span("keyword")]
+ | identifier [span("identifier")]
+ | special [span("special")]
+ | string_ [span("string")]
+ | char_ [span("char")]
+ | number [span("number")]
+ | u8_codepoint_p [unexpected_char]
)
;
macro =
// must not be followed by alpha or underscore
- cl::eps_p(self.escape_actions.macro
+ cl::eps_p(self.actions.state.macro
>> (cl::eps_p - (cl::alpha_p | '_')))
- >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)]
+ >> self.actions.state.macro
+ [do_macro]
;
escape =
- cl::str_p("``") [pre_escape_back(self.escape_actions)]
+ cl::str_p("``") [pre_escape_back]
>>
(
(
@@ -275,29 +312,46 @@ namespace quickbook
)
|
(
- cl::eps_p [self.escape_actions.error]
+ cl::eps_p [error]
>> *cl::anychar_p
)
- ) [post_escape_back(self.out, self.escape_actions)]
+ ) [post_escape_back]
;
preprocessor
= '#' >> *cl::space_p >> ((cl::alpha_p | '_') >> *(cl::alnum_p | '_'))
;
+ inline_callout
+ = cl::confix_p(
+ "/*<" >> *cl::space_p,
+ (*cl::anychar_p) [mark_text],
+ ">*/"
+ )
+ ;
+
+ line_callout
+ = cl::confix_p(
+ "/*<<" >> *cl::space_p,
+ (*cl::anychar_p) [mark_text],
+ ">>*/"
+ )
+ >> *cl::space_p
+ ;
+
comment
- = cl::str_p("//") [span_start("comment", self.out)]
+ = cl::str_p("//") [span_start("comment")]
>> *( escape
| (+(cl::anychar_p - (cl::eol_p | "``")))
- [plain_char(self.out)]
+ [plain_char]
)
- >> cl::eps_p [span_end(self.out)]
- | cl::str_p("/*") [span_start("comment", self.out)]
+ >> cl::eps_p [span_end]
+ | cl::str_p("/*") [span_start("comment")]
>> *( escape
| (+(cl::anychar_p - (cl::str_p("*/") | "``")))
- [plain_char(self.out)]
+ [plain_char]
)
- >> (!cl::str_p("*/")) [span_end(self.out)]
+ >> (!cl::str_p("*/")) [span_end]
;
keyword
@@ -308,7 +362,7 @@ namespace quickbook
= +cl::chset_p("~!%^&*()+={[}]:;,<.>?/|\\-")
;
- string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\');
+ string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\');
string_
= !cl::as_lower_d['l'] >> cl::confix_p('"', *string_char, '"')
@@ -333,7 +387,9 @@ namespace quickbook
}
cl::rule<Scanner>
- program, macro, preprocessor, comment, special, string_,
+ program, macro, preprocessor,
+ inline_callout, line_callout, comment,
+ special, string_,
char_, number, identifier, keyword, escape,
string_char;
@@ -343,50 +399,63 @@ namespace quickbook
start() const { return program; }
};
- collector& out;
- actions& escape_actions;
+ syntax_highlight_actions& actions;
};
// Grammar for Python highlighting
// See also: The Python Reference Manual
// http://docs.python.org/ref/ref.html
- struct python_highlight
- : public cl::grammar<python_highlight>
+ struct python_highlight : public cl::grammar<python_highlight>
{
- python_highlight(collector& out, actions& escape_actions)
- : out(out), escape_actions(escape_actions) {}
+ python_highlight(syntax_highlight_actions& actions)
+ : actions(actions) {}
template <typename Scanner>
struct definition
{
definition(python_highlight const& self)
- : g(self.escape_actions.grammar())
+ : g(self.actions.state.grammar())
{
+ member_action1<syntax_highlight_actions, char const*>
+ span(self.actions, &syntax_highlight_actions::span),
+ span_start(self.actions, &syntax_highlight_actions::span_start);
+ member_action<syntax_highlight_actions>
+ span_end(self.actions, &syntax_highlight_actions::span_end),
+ unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char),
+ plain_char(self.actions, &syntax_highlight_actions::plain_char),
+ pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back),
+ post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back),
+ mark_text(self.actions, &syntax_highlight_actions::mark_text),
+ callout(self.actions, &syntax_highlight_actions::callout);
+ member_action_value<syntax_highlight_actions, std::string const&>
+ do_macro(self.actions, &syntax_highlight_actions::do_macro);
+ error_action error(self.actions.state);
+
program
=
- *( (+cl::space_p) [plain_char(self.out)]
+ *( (+cl::space_p) [plain_char]
| macro
| escape
| comment
- | keyword [span("keyword", self.out)]
- | identifier [span("identifier", self.out)]
- | special [span("special", self.out)]
- | string_ [span("string", self.out)]
- | number [span("number", self.out)]
- | cl::repeat_p(1)[cl::anychar_p]
- [unexpected_char(self.out, self.escape_actions)]
+ | keyword [span("keyword")]
+ | identifier [span("identifier")]
+ | special [span("special")]
+ | string_ [span("string")]
+ | number [span("number")]
+ | u8_codepoint_p [unexpected_char]
)
;
macro =
// must not be followed by alpha or underscore
- cl::eps_p(self.escape_actions.macro
+ cl::eps_p(self.actions.state.macro
>> (cl::eps_p - (cl::alpha_p | '_')))
- >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)]
+ >> self.actions.state.macro
+ [do_macro]
;
escape =
- cl::str_p("``") [pre_escape_back(self.escape_actions)]
+ cl::str_p("``") [pre_escape_back]
>>
(
(
@@ -398,19 +467,19 @@ namespace quickbook
)
|
(
- cl::eps_p [self.escape_actions.error]
+ cl::eps_p [error]
>> *cl::anychar_p
)
- ) [post_escape_back(self.out, self.escape_actions)]
+ ) [post_escape_back]
;
comment
- = cl::str_p("#") [span_start("comment", self.out)]
+ = cl::str_p("#") [span_start("comment")]
>> *( escape
| (+(cl::anychar_p - (cl::eol_p | "``")))
- [plain_char(self.out)]
+ [plain_char]
)
- >> cl::eps_p [span_end(self.out)]
+ >> cl::eps_p [span_end]
;
keyword
@@ -429,7 +498,7 @@ namespace quickbook
= ! string_prefix >> (long_string | short_string)
;
- string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\');
+ string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\');
short_string
= cl::confix_p('\'', * string_char, '\'') |
@@ -468,40 +537,47 @@ namespace quickbook
start() const { return program; }
};
- collector& out;
- actions& escape_actions;
+ syntax_highlight_actions& actions;
};
// Grammar for plain text (no actual highlighting)
- struct teletype_highlight
- : public cl::grammar<teletype_highlight>
+ struct teletype_highlight : public cl::grammar<teletype_highlight>
{
- teletype_highlight(collector& out, actions& escape_actions)
- : out(out), escape_actions(escape_actions) {}
+ teletype_highlight(syntax_highlight_actions& actions)
+ : actions(actions) {}
template <typename Scanner>
struct definition
{
definition(teletype_highlight const& self)
- : g(self.escape_actions.grammar())
+ : g(self.actions.state.grammar())
{
+ member_action<syntax_highlight_actions>
+ plain_char(self.actions, &syntax_highlight_actions::plain_char),
+ pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back),
+ post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back);
+ member_action_value<syntax_highlight_actions, std::string const&>
+ do_macro(self.actions, &syntax_highlight_actions::do_macro);
+ error_action error(self.actions.state);
+
program
=
*( macro
| escape
- | cl::repeat_p(1)[cl::anychar_p] [plain_char(self.out)]
+ | u8_codepoint_p [plain_char]
)
;
macro =
// must not be followed by alpha or underscore
- cl::eps_p(self.escape_actions.macro
+ cl::eps_p(self.actions.state.macro
>> (cl::eps_p - (cl::alpha_p | '_')))
- >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)]
+ >> self.actions.state.macro
+ [do_macro]
;
escape =
- cl::str_p("``") [pre_escape_back(self.escape_actions)]
+ cl::str_p("``") [pre_escape_back]
>>
(
(
@@ -513,10 +589,10 @@ namespace quickbook
)
|
(
- cl::eps_p [self.escape_actions.error]
+ cl::eps_p [error]
>> *cl::anychar_p
)
- ) [post_escape_back(self.out, self.escape_actions)]
+ ) [post_escape_back]
;
}
@@ -528,32 +604,32 @@ namespace quickbook
start() const { return program; }
};
- collector& out;
- actions& escape_actions;
+ syntax_highlight_actions& actions;
};
std::string syntax_highlight(
parse_iterator first,
parse_iterator last,
- actions& escape_actions,
- std::string const& source_mode)
+ quickbook::state& state,
+ std::string const& source_mode,
+ bool is_block)
{
- quickbook::collector temp;
+ syntax_highlight_actions syn_actions(state, is_block);
// print the code with syntax coloring
if (source_mode == "c++")
{
- cpp_highlight cpp_p(temp, escape_actions);
+ cpp_highlight cpp_p(syn_actions);
boost::spirit::classic::parse(first, last, cpp_p);
}
else if (source_mode == "python")
{
- python_highlight python_p(temp, escape_actions);
+ python_highlight python_p(syn_actions);
boost::spirit::classic::parse(first, last, python_p);
}
else if (source_mode == "teletype")
{
- teletype_highlight teletype_p(temp, escape_actions);
+ teletype_highlight teletype_p(syn_actions);
boost::spirit::classic::parse(first, last, teletype_p);
}
else
@@ -562,7 +638,7 @@ namespace quickbook
}
std::string str;
- temp.swap(str);
+ syn_actions.out.swap(str);
return str;
}
diff --git a/tools/quickbook/src/utils.cpp b/tools/quickbook/src/utils.cpp
index 0defe6d182..3a5ee42e4d 100644
--- a/tools/quickbook/src/utils.cpp
+++ b/tools/quickbook/src/utils.cpp
@@ -62,23 +62,4 @@ namespace quickbook { namespace detail
}
return uri;
}
-
- file_type get_file_type(std::string const& extension)
- {
- static std::map<std::string, file_type> ftypes;
- if (ftypes.empty())
- {
- // init the map of types
- ftypes["cpp"] = cpp_file;
- ftypes["hpp"] = cpp_file;
- ftypes["h"] = cpp_file;
- ftypes["c"] = cpp_file;
- ftypes["cxx"] = cpp_file;
- ftypes["hxx"] = cpp_file;
- ftypes["ipp"] = cpp_file;
- ftypes["py"] = python_file;
- }
- return ftypes[extension];
- }
-
}}
diff --git a/tools/quickbook/src/utils.hpp b/tools/quickbook/src/utils.hpp
index e7afa05e1b..9170f81043 100644
--- a/tools/quickbook/src/utils.hpp
+++ b/tools/quickbook/src/utils.hpp
@@ -33,17 +33,6 @@ namespace quickbook { namespace detail {
}
std::string escape_uri(std::string uri);
-
- // given a file extension, return the type of the source file
- // we'll have an internal database for known file types.
-
- enum file_type
- {
- cpp_file
- , python_file
- };
-
- file_type get_file_type(std::string const& extension);
}}
#endif // BOOST_SPIRIT_QUICKBOOK_UTILS_HPP
diff --git a/tools/quickbook/src/values.cpp b/tools/quickbook/src/values.cpp
index 7c3521d50b..904cc8b38f 100644
--- a/tools/quickbook/src/values.cpp
+++ b/tools/quickbook/src/values.cpp
@@ -765,6 +765,11 @@ namespace quickbook
back_ = merge_sort(&head_);
assert(*back_ == &value_list_end_impl::instance);
}
+
+ bool value_list_builder::empty() const
+ {
+ return head_ == &value_list_end_impl::instance;
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -799,16 +804,6 @@ namespace quickbook
return value(new detail::value_list_impl(current, list_tag));
}
- void value_builder::reset() {
- detail::value_list_builder new_builder;
- current.swap(new_builder);
- list_tag = value::default_tag;
- }
-
- void value_builder::set_tag(value::tag_type tag) {
- list_tag = tag;
- }
-
void value_builder::insert(value const& item) {
current.append(item.value_);
}
@@ -822,9 +817,8 @@ namespace quickbook
}
void value_builder::start_list(value::tag_type tag) {
- value::tag_type saved_tag = tag;
save();
- list_tag = saved_tag;
+ list_tag = tag;
}
void value_builder::finish_list() {
@@ -842,6 +836,11 @@ namespace quickbook
current.sort();
}
+ bool value_builder::empty() const
+ {
+ return current.empty();
+ }
+
////////////////////////////////////////////////////////////////////////////
// Iterator
diff --git a/tools/quickbook/src/values.hpp b/tools/quickbook/src/values.hpp
index 2380b0d5dc..d637ea2adb 100644
--- a/tools/quickbook/src/values.hpp
+++ b/tools/quickbook/src/values.hpp
@@ -211,6 +211,8 @@ namespace quickbook
void append(value_node*);
void sort();
+
+ bool empty() const;
private:
value_node* head_;
value_node** back_;
@@ -269,8 +271,6 @@ namespace quickbook
value release();
- void reset();
- void set_tag(value::tag_type);
void insert(value const&);
void extend(value const&);
@@ -279,6 +279,8 @@ namespace quickbook
void clear_list();
void sort_list();
+ bool empty() const;
+
private:
detail::value_list_builder current;
value::tag_type list_tag;
diff --git a/tools/quickbook/test/Jamfile.v2 b/tools/quickbook/test/Jamfile.v2
index fca35b5be4..900b4758a2 100644
--- a/tools/quickbook/test/Jamfile.v2
+++ b/tools/quickbook/test/Jamfile.v2
@@ -26,6 +26,7 @@ test-suite quickbook.test :
[ quickbook-test anchor-1_6 ]
[ quickbook-test blocks-1_5 ]
[ quickbook-test callouts-1_5 ]
+ [ quickbook-test callouts-1_7 ]
[ quickbook-test code-1_1 ]
[ quickbook-test code-1_5 ]
[ quickbook-test code_cpp-1_5 ]
@@ -34,6 +35,7 @@ test-suite quickbook.test :
[ quickbook-error-test code_python_mismatched_escape-1_4-fail ]
[ quickbook-test code_snippet-1_1 ]
[ quickbook-test code_teletype-1_5 ]
+ [ quickbook-error-test code_unclosed_block-1_6-fail ]
[ quickbook-test command_line_macro-1_1 : : :
<quickbook-test-define>__macro__=*bold*
<quickbook-test-define>__empty__ ]
@@ -65,6 +67,7 @@ test-suite quickbook.test :
[ quickbook-error-test include_win_path-1_6-fail ]
[ quickbook-test link-1_1 ]
[ quickbook-test link-1_6 ]
+ [ quickbook-test link-1_7 ]
[ quickbook-test list_test-1_5 ]
[ quickbook-test list_test-1_6 ]
[ quickbook-test macro-1_5 ]
@@ -82,6 +85,7 @@ test-suite quickbook.test :
[ quickbook-test section-1_5-unclosed ]
[ quickbook-test section-1_5 ]
[ quickbook-test simple_markup-1_5 ]
+ [ quickbook-test source_mode-1_7 ]
[ quickbook-test svg-1_1 ]
[ quickbook-test table-1_3 ]
[ quickbook-test table-1_5 ]
@@ -106,7 +110,7 @@ test-suite quickbook.test :
[ quickbook-error-test variablelist-1_5-fail ]
[ quickbook-test variablelist-1_5 ]
[ quickbook-error-test version-0_1-fail ]
- [ quickbook-error-test version-1_7-fail ]
+ [ quickbook-error-test version-1_8-fail ]
[ quickbook-error-test version-2_0-fail ]
[ quickbook-test xml_escape-1_2 ]
[ quickbook-test xml_escape-1_5 ]
diff --git a/tools/quickbook/test/callouts-1_7.gold b/tools/quickbook/test/callouts-1_7.gold
new file mode 100644
index 0000000000..5cf0dc59ef
--- /dev/null
+++ b/tools/quickbook/test/callouts-1_7.gold
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="callout_tests" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Callout Tests</title>
+ <para>
+ Example 1:
+ </para>
+ <para>
+ Now we can define a function that simulates an ordinary six-sided die.
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c0" linkends="callout_tests.c1" />
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c0" id="callout_tests.c1">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 2:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.c2" linkends="callout_tests.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c2" id="callout_tests.c3">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 3:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.c4" linkends="callout_tests.c5" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c4" id="callout_tests.c5">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 3 (again!):
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.c6" linkends="callout_tests.c7" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c6" id="callout_tests.c7">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 4:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.c8" linkends="callout_tests.c9" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+ <co id="callout_tests.c10" linkends="callout_tests.c11" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c12" linkends="callout_tests.c13" />
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c8" id="callout_tests.c9">
+ <para>
+ callout 1
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.c10" id="callout_tests.c11">
+ <para>
+ callout 2
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.c12" id="callout_tests.c13">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+<programlisting><co id="callout_tests.c14" linkends="callout_tests.c15" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c16" linkends="callout_tests.c17" />
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.c14" id="callout_tests.c15">
+ <para>
+ callout 2
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.c16" id="callout_tests.c17">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+ <section id="callout_tests.test_section">
+ <title><link linkend="callout_tests.test_section">Try callouts in a section</link></title>
+ <para>
+ Example 1:
+ </para>
+ <para>
+ Now we can define a function that simulates an ordinary six-sided die.
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c0" linkends="callout_tests.test_section.c1" />
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c0" id="callout_tests.test_section.c1">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 2:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.test_section.c2" linkends="callout_tests.test_section.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c2" id="callout_tests.test_section.c3">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 3:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.test_section.c4" linkends="callout_tests.test_section.c5" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c4" id="callout_tests.test_section.c5">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 3 (again!):
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.test_section.c6" linkends="callout_tests.test_section.c7" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c6" id="callout_tests.test_section.c7">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ Example 4:
+ </para>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.test_section.c8" linkends="callout_tests.test_section.c9" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+ <co id="callout_tests.test_section.c10" linkends="callout_tests.test_section.c11" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c12" linkends="callout_tests.test_section.c13" />
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c8" id="callout_tests.test_section.c9">
+ <para>
+ callout 1
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.test_section.c10" id="callout_tests.test_section.c11">
+ <para>
+ callout 2
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.test_section.c12" id="callout_tests.test_section.c13">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+<programlisting><co id="callout_tests.test_section.c14" linkends="callout_tests.test_section.c15" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c16" linkends="callout_tests.test_section.c17" />
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.test_section.c14" id="callout_tests.test_section.c15">
+ <para>
+ callout 2
+ </para>
+ </callout>
+ <callout arearefs="callout_tests.test_section.c16" id="callout_tests.test_section.c17">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+ </section>
+ <section id="callout_tests.blocks">
+ <title><link linkend="callout_tests.blocks">Callouts in code blocks</link></title>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.blocks.c0" linkends="callout_tests.blocks.c1" />
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.blocks.c0" id="callout_tests.blocks.c1">
+ <para>
+ create a uniform_int distribution
+ </para>
+ </callout>
+ </calloutlist>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
+ <co id="callout_tests.blocks.c2" linkends="callout_tests.blocks.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase>
+<phrase role="special">}</phrase>
+</programlisting>
+ <calloutlist>
+ <callout arearefs="callout_tests.blocks.c2" id="callout_tests.blocks.c3">
+ <important>
+ <para>
+ test
+ </para>
+ </important>
+ </callout>
+ </calloutlist>
+ <para>
+ <code><phrase role="comment">/*&lt; This shouldn't be a callout &gt;*/</phrase></code>
+ </para>
+ </section>
+</article>
diff --git a/tools/quickbook/test/callouts-1_7.quickbook b/tools/quickbook/test/callouts-1_7.quickbook
new file mode 100644
index 0000000000..fd3d9ee8b8
--- /dev/null
+++ b/tools/quickbook/test/callouts-1_7.quickbook
@@ -0,0 +1,68 @@
+[article Callout Tests
+ [quickbook 1.7]
+]
+
+[import callouts.cpp]
+
+Example 1:
+
+[example1]
+
+Example 2:
+
+[example2]
+
+Example 3:
+
+[example3]
+
+Example 3 (again!):
+
+[example3]
+
+Example 4:
+
+[example4]
+[example4a]
+
+[section:test_section Try callouts in a section]
+
+Example 1:
+
+[example1]
+
+Example 2:
+
+[example2]
+
+Example 3:
+
+[example3]
+
+Example 3 (again!):
+
+[example3]
+
+Example 4:
+
+[example4]
+[example4a]
+
+[endsect]
+
+[section:blocks Callouts in code blocks]
+
+ int roll_die() {
+ boost::uniform_int<> dist(1, 6); /*< create a uniform_int distribution >*/
+ }
+
+```
+int roll_die() {
+ /*<< [important test] >>*/
+ boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist);
+}
+```
+
+`/*< This shouldn't be a callout >*/`
+
+[endsect] \ No newline at end of file
diff --git a/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook b/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook
new file mode 100644
index 0000000000..f02887c440
--- /dev/null
+++ b/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook
@@ -0,0 +1,4 @@
+[article Odd code markup. [quickbook 1.6] ]
+
+``
+int main() {}
diff --git a/tools/quickbook/test/doc-info/Jamfile.v2 b/tools/quickbook/test/doc-info/Jamfile.v2
index f7d262c050..9d4913b81c 100644
--- a/tools/quickbook/test/doc-info/Jamfile.v2
+++ b/tools/quickbook/test/doc-info/Jamfile.v2
@@ -16,6 +16,8 @@ test-suite quickbook.test :
[ quickbook-test author1 ]
[ quickbook-test author2 ]
[ quickbook-test empty-attributes ]
+ [ quickbook-test escaped_attributes1-1_7 ]
+ [ quickbook-test escaped_attributes2-1_7 ]
[ quickbook-test duplicates-1.1 ]
[ quickbook-test duplicates-1.5 ]
[ quickbook-test source-mode-1.4 ]
diff --git a/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold
new file mode 100644
index 0000000000..b6425d910e
--- /dev/null
+++ b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<library id="escaped_name" name="Escaped name" dirname="escaped_name" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <libraryinfo>
+ <copyright>
+ <year>1325</year> <holder>John Doe</holder>
+ </copyright>
+ <librarycategory name="category:test"></librarycategory> <author>
+ <firstname>John</firstname>
+ <surname>Doe</surname>
+ <email>john.doe@example.com</email>
+</author>
+ </libraryinfo>
+ <title>Escaped name</title>
+</library>
diff --git a/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook
new file mode 100644
index 0000000000..e701613751
--- /dev/null
+++ b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook
@@ -0,0 +1,11 @@
+[library Escaped name
+[quickbook 1.7]
+[copyright 1325 John Doe]
+'''<author>
+ <firstname>John</firstname>
+ <surname>Doe</surname>
+ <email>john.doe@example.com</email>
+</author>'''
+[category test]
+]
+
diff --git a/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold
new file mode 100644
index 0000000000..259111ac43
--- /dev/null
+++ b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="multiple_escaped_attributes" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Multiple escaped attributes</title>
+ <articleinfo>
+ <author>
+ <firstname>John</firstname>
+ <surname>Doe</surname>
+ <email>john.doe@example.com</email>
+</author><orgname>Acme Corporation</orgname></articleinfo>
+</article>
diff --git a/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook
new file mode 100644
index 0000000000..70676f8a16
--- /dev/null
+++ b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook
@@ -0,0 +1,10 @@
+[article Multiple escaped attributes
+[quickbook 1.7]
+'''<author>
+ <firstname>John</firstname>
+ <surname>Doe</surname>
+ <email>john.doe@example.com</email>
+</author>'''
+'''<orgname>Acme Corporation</orgname>'''
+]
+
diff --git a/tools/quickbook/test/link-1_7.gold b/tools/quickbook/test/link-1_7.gold
new file mode 100644
index 0000000000..f3eec12e74
--- /dev/null
+++ b/tools/quickbook/test/link-1_7.gold
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="link_tests" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Link tests</title>
+ <section id="link_tests.different_types_of_links">
+ <title><link linkend="link_tests.different_types_of_links">Different types of
+ links</link></title>
+ <para>
+ <ulink url="http://www.boost.org/">http://www.boost.org/</ulink> <ulink url="http://www.boost.org/">Boost</ulink>
+ <link linkend="link-id">link-id</link> <link linkend="link-id">Link Text</link>
+ <anchor id="link-id"/><functionname alt="foo">foo</functionname> <functionname
+ alt="foo">link text</functionname> <classname alt="foo">foo</classname> <classname
+ alt="foo">link text</classname> <methodname alt="foo">foo</methodname> <methodname
+ alt="foo">link text</methodname> <enumname alt="foo">foo</enumname> <enumname
+ alt="foo">link text</enumname> <macroname alt="foo">foo</macroname> <macroname
+ alt="foo">link text</macroname> <headername alt="foo">foo</headername> <headername
+ alt="foo">link text</headername> <conceptname alt="foo">foo</conceptname>
+ <conceptname alt="foo">link text</conceptname> <globalname alt="foo">foo</globalname>
+ <globalname alt="foo">link text</globalname>
+ </para>
+ <para>
+ <link linkend="link">description</link>
+ </para>
+ <para>
+ <link linkend="link[Hello]">description</link>
+ </para>
+ </section>
+ <section id="link_tests.side_by_side_links">
+ <title><link linkend="link_tests.side_by_side_links">Side-by-side links</link></title>
+ <para>
+ <link linkend="x">x</link> and <link linkend="y">y</link> are two distinct
+ links, which should be separated by whitespace when they appear together as
+ in <link linkend="x">x</link> <link linkend="y">y</link>. Also in <link linkend="x">x</link>
+ <link linkend="y">y</link>, and in <link linkend="x">x</link> <link linkend="y">y</link>
+ as well.
+ </para>
+ </section>
+ <section id="link_tests.templates_is_links">
+ <title><link linkend="link_tests.templates_is_links">Templates is links....</link></title>
+ <para>
+ <link linkend="blah.x2">Templated link?</link>
+ </para>
+ </section>
+</article>
diff --git a/tools/quickbook/test/link-1_7.quickbook b/tools/quickbook/test/link-1_7.quickbook
new file mode 100644
index 0000000000..8e146b9706
--- /dev/null
+++ b/tools/quickbook/test/link-1_7.quickbook
@@ -0,0 +1,52 @@
+[article Link tests
+[quickbook 1.7]
+]
+
+[section Different types of links]
+
+[@http://www.boost.org/]
+[@ http://www.boost.org/ Boost]
+[link link-id]
+[link link-id Link Text]
+[#link-id]
+[funcref foo]
+[funcref foo link text]
+[classref foo]
+[classref foo link text]
+[memberref foo]
+[memberref foo link text]
+[enumref foo]
+[enumref foo link text]
+[macroref foo]
+[macroref foo link text]
+[headerref foo]
+[headerref foo link text]
+[conceptref foo]
+[conceptref foo link text]
+[globalref foo]
+[globalref foo link text]
+
+[link link[/ comment]description]
+
+[link link\[Hello\] description]
+
+
+[endsect]
+
+[section Side-by-side links]
+
+[link x] and [link y] are two distinct links, which should be separated by
+whitespace when they appear together as in [link x] [link y]. Also in [link x]
+[link y], and in
+[link x]
+[link y]
+as well.
+
+[endsect]
+
+[section Templates is links....]
+
+[template thing[]x]
+[link blah.[thing]2 Templated link?]
+
+[endsect]
diff --git a/tools/quickbook/test/list_test-1_5.gold b/tools/quickbook/test/list_test-1_5.gold
index a1b44d829e..4d25aa7cce 100644
--- a/tools/quickbook/test/list_test-1_5.gold
+++ b/tools/quickbook/test/list_test-1_5.gold
@@ -383,4 +383,20 @@
</listitem>
</itemizedlist>
</section>
+ <section id="list_test.list_immediately_following_markup_2">
+ <title><link linkend="list_test.list_immediately_following_markup_2">List immediately
+ following markup 2</link></title>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ One [section Nested section]
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Two [endsect]
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </section>
</article>
diff --git a/tools/quickbook/test/list_test-1_5.quickbook b/tools/quickbook/test/list_test-1_5.quickbook
index ab78e6f588..64b391a614 100644
--- a/tools/quickbook/test/list_test-1_5.quickbook
+++ b/tools/quickbook/test/list_test-1_5.quickbook
@@ -98,3 +98,11 @@ Don't end list with comment 2:
* Three
[endsect]
+
+[section List immediately following markup 2]
+* One
+[section Nested section]
+* Two
+[endsect]
+
+[endsect]
diff --git a/tools/quickbook/test/list_test-1_6.gold b/tools/quickbook/test/list_test-1_6.gold
index 223509a590..f0055257ab 100644
--- a/tools/quickbook/test/list_test-1_6.gold
+++ b/tools/quickbook/test/list_test-1_6.gold
@@ -420,6 +420,28 @@
</listitem>
</itemizedlist>
</section>
+ <section id="list_test.list_immediately_following_mark0">
+ <title><link linkend="list_test.list_immediately_following_mark0">List immediately
+ following markup 2</link></title>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ One
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <section id="list_test.list_immediately_following_mark0.nested_section">
+ <title><link linkend="list_test.list_immediately_following_mark0.nested_section">Nested
+ section</link></title>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Two
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
<section id="list_test.paragraphs_in_list_items">
<title><link linkend="list_test.paragraphs_in_list_items">Paragraphs in list
items</link></title>
@@ -473,4 +495,32 @@
</listitem>
</itemizedlist>
</section>
+ <section id="list_test.indented_code_blocks_in_lists">
+ <title><link linkend="list_test.indented_code_blocks_in_lists">Indented code
+ blocks in lists</link></title>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A
+<programlisting><phrase role="identifier">B</phrase>
+</programlisting>
+ <para>
+ C
+ </para>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ D
+<programlisting><phrase role="identifier">E</phrase>
+</programlisting>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ F
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </section>
</article>
diff --git a/tools/quickbook/test/list_test-1_6.quickbook b/tools/quickbook/test/list_test-1_6.quickbook
index fd01b389d5..dbba74258e 100644
--- a/tools/quickbook/test/list_test-1_6.quickbook
+++ b/tools/quickbook/test/list_test-1_6.quickbook
@@ -103,6 +103,13 @@ Don't end list with comment 2:
[endsect]
+[section List immediately following markup 2]
+* One
+[section Nested section]
+* Two
+[endsect]
+[endsect]
+
[section Paragraphs in list items]
* A1
@@ -125,4 +132,16 @@ Don't end list with comment 2:
D2
-[endsect] \ No newline at end of file
+[endsect]
+
+[section Indented code blocks in lists]
+
+* A
+
+ B
+ C
+* D
+
+ E
+* F
+[endsect]
diff --git a/tools/quickbook/test/python/include_path.qbk b/tools/quickbook/test/python/include_path.qbk
new file mode 100644
index 0000000000..c9a4dcd981
--- /dev/null
+++ b/tools/quickbook/test/python/include_path.qbk
@@ -0,0 +1,4 @@
+[quickbook 1.5]
+[article Include Path]
+[include a.qbk]
+[include b.qbk]
diff --git a/tools/quickbook/test/python/include_path_deps.txt b/tools/quickbook/test/python/include_path_deps.txt
new file mode 100644
index 0000000000..994d776ee6
--- /dev/null
+++ b/tools/quickbook/test/python/include_path_deps.txt
@@ -0,0 +1,3 @@
+include_path.qbk
+sub1/a.qbk
+sub2/b.qbk
diff --git a/tools/quickbook/test/python/include_path_locs.txt b/tools/quickbook/test/python/include_path_locs.txt
new file mode 100644
index 0000000000..aaffb8d13f
--- /dev/null
+++ b/tools/quickbook/test/python/include_path_locs.txt
@@ -0,0 +1,6 @@
++ include_path.qbk
+- a.qbk
++ sub1/a.qbk
+- b.qbk
+- sub1/b.qbk
++ sub2/b.qbk
diff --git a/tools/quickbook/test/python/missing_relative.qbk b/tools/quickbook/test/python/missing_relative.qbk
new file mode 100644
index 0000000000..8fdc0ee049
--- /dev/null
+++ b/tools/quickbook/test/python/missing_relative.qbk
@@ -0,0 +1,6 @@
+[quickbook 1.5]
+[article Missing Relative]
+
+[include ../missing.qbk]
+[include missing-dir/x.qbk]
+[include missing-dir/../../x.qbk]
diff --git a/tools/quickbook/test/python/missing_relative_deps.txt b/tools/quickbook/test/python/missing_relative_deps.txt
new file mode 100644
index 0000000000..a9de670365
--- /dev/null
+++ b/tools/quickbook/test/python/missing_relative_deps.txt
@@ -0,0 +1 @@
+missing_relative.qbk
diff --git a/tools/quickbook/test/python/missing_relative_locs.txt b/tools/quickbook/test/python/missing_relative_locs.txt
new file mode 100644
index 0000000000..69b51f28f4
--- /dev/null
+++ b/tools/quickbook/test/python/missing_relative_locs.txt
@@ -0,0 +1,4 @@
++ missing_relative.qbk
+- ../missing.qbk
+- missing-dir/x.qbk
+- missing-dir/../../x.qbk
diff --git a/tools/quickbook/test/python/output-deps.py b/tools/quickbook/test/python/output-deps.py
new file mode 100644
index 0000000000..7b77c27d84
--- /dev/null
+++ b/tools/quickbook/test/python/output-deps.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+
+import sys, os, subprocess, tempfile, re
+
+def main(args, directory):
+ if len(args) != 1:
+ print "Usage: output-deps.py quickbook-command"
+ exit(1)
+ quickbook_command = args[0]
+
+ failures = 0
+ failures += run_quickbook(quickbook_command, 'svg_missing.qbk',
+ deps_gold = 'svg_missing_deps.txt')
+ failures += run_quickbook(quickbook_command, 'svg_missing.qbk',
+ locations_gold = 'svg_missing_locs.txt')
+ failures += run_quickbook(quickbook_command, 'missing_relative.qbk',
+ deps_gold = 'missing_relative_deps.txt',
+ locations_gold = 'missing_relative_locs.txt')
+ failures += run_quickbook(quickbook_command, 'include_path.qbk',
+ deps_gold = 'include_path_deps.txt',
+ locations_gold = 'include_path_locs.txt',
+ input_path = ['sub1', 'sub2'])
+
+ if failures == 0:
+ print "Success"
+ else:
+ print "Failures:",failures
+ exit(failures)
+
+def run_quickbook(quickbook_command, filename, output_gold = None,
+ deps_gold = None, locations_gold = None, input_path = []):
+ failures = 0
+
+ command = [quickbook_command, '--debug', filename]
+
+ output_filename = None
+ if output_gold:
+ output_filename = temp_filename('.qbk')
+ command.extend(['--output-file', output_filename])
+
+ deps_filename = None
+ if deps_gold:
+ deps_filename = temp_filename('.txt')
+ command.extend(['--output-deps', deps_filename])
+
+ locations_filename = None
+ if locations_gold:
+ locations_filename = temp_filename('.txt')
+ command.extend(['--output-checked-locations', locations_filename])
+
+ try:
+ for path in input_path:
+ command.extend(['-I', path])
+ print 'Running: ' + ' '.join(command)
+ print
+ exit_code = subprocess.call(command)
+ print
+ success = not exit_code
+
+ if output_filename:
+ output = load_file(output_filename)
+ else:
+ output = None
+
+ if deps_filename:
+ deps = load_dependencies(deps_filename)
+ else:
+ deps = None
+
+ if locations_filename:
+ locations = load_locations(locations_filename)
+ else:
+ locations = None
+ finally:
+ if output_filename: os.unlink(output_filename)
+ if deps_filename: os.unlink(deps_filename)
+
+ if deps_gold:
+ gold = load_dependencies(deps_gold, adjust_paths = True)
+ if deps != gold:
+ failures = failures + 1
+ print "Dependencies don't match:"
+ print "Gold:", gold
+ print "Result:", deps
+ print
+
+ if locations_gold:
+ gold = load_locations(locations_gold, adjust_paths = True)
+ if locations != gold:
+ failures = failures + 1
+ print "Dependencies don't match:"
+ print "Gold:", gold
+ print "Result:", locations
+ print
+
+ if output_gold:
+ gold = load_file(output_gold)
+ if gold != output:
+ failures = failures + 1
+ print "Output doesn't match:"
+ print
+ print gold
+ print
+ print output
+ print
+
+ return failures
+
+def load_dependencies(filename, adjust_paths = False):
+ dependencies = set()
+ f = open(filename, 'r')
+ for path in f:
+ if adjust_paths:
+ path = os.path.realpath(path)
+ if path in dependencies:
+ raise Exception("Duplicate path (%1s) in %2s" % (path, filename))
+ dependencies.add(path)
+ return dependencies
+
+def load_locations(filename, adjust_paths = False):
+ line_matcher = re.compile("^([+-]) (.*)$")
+ dependencies = {}
+ f = open(filename, 'r')
+ for line in f:
+ m = line_matcher.match(line)
+ if not m:
+ raise Exception("Invalid dependency file: %1s" % filename)
+ found = m.group(1) == '+'
+ path = m.group(2)
+ if adjust_paths:
+ path = os.path.realpath(path)
+ if path in dependencies:
+ raise Exception("Duplicate path (%1s) in %2s" % (path, filename))
+ dependencies[path] = found
+ return dependencies
+
+def temp_filename(extension):
+ file = tempfile.mkstemp(suffix = extension)
+ os.close(file[0])
+ return file[1]
+
+def load_file(filename):
+ f = open(filename, 'r')
+ try:
+ return f.read()
+ finally:
+ f.close()
+
+ return None
+
+main(sys.argv[1:], os.path.dirname(sys.argv[0]))
diff --git a/tools/quickbook/test/python/sub1/a.qbk b/tools/quickbook/test/python/sub1/a.qbk
new file mode 100644
index 0000000000..7898192261
--- /dev/null
+++ b/tools/quickbook/test/python/sub1/a.qbk
@@ -0,0 +1 @@
+a
diff --git a/tools/quickbook/test/python/sub2/b.qbk b/tools/quickbook/test/python/sub2/b.qbk
new file mode 100644
index 0000000000..6178079822
--- /dev/null
+++ b/tools/quickbook/test/python/sub2/b.qbk
@@ -0,0 +1 @@
+b
diff --git a/tools/quickbook/test/python/svg_missing.qbk b/tools/quickbook/test/python/svg_missing.qbk
new file mode 100644
index 0000000000..2b25c2f3b6
--- /dev/null
+++ b/tools/quickbook/test/python/svg_missing.qbk
@@ -0,0 +1,3 @@
+[article Dependencies for missing svg]
+
+[$missing.svg]
diff --git a/tools/quickbook/test/python/svg_missing_deps.txt b/tools/quickbook/test/python/svg_missing_deps.txt
new file mode 100644
index 0000000000..25d1c0e502
--- /dev/null
+++ b/tools/quickbook/test/python/svg_missing_deps.txt
@@ -0,0 +1 @@
+svg_missing.qbk
diff --git a/tools/quickbook/test/python/svg_missing_locs.txt b/tools/quickbook/test/python/svg_missing_locs.txt
new file mode 100644
index 0000000000..379d4142f0
--- /dev/null
+++ b/tools/quickbook/test/python/svg_missing_locs.txt
@@ -0,0 +1,2 @@
+- html/missing.svg
++ svg_missing.qbk
diff --git a/tools/quickbook/test/source_mode-1_7.gold b/tools/quickbook/test/source_mode-1_7.gold
new file mode 100644
index 0000000000..e40bae8608
--- /dev/null
+++ b/tools/quickbook/test/source_mode-1_7.gold
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="source_mode_test" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Source Mode Test</title>
+ <informaltable frame="all">
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase></programlisting>
+ </entry>
+ <entry>
+<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase></programlisting>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+<programlisting>Plain text...</programlisting>
+ <para>
+ <code><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase
+ role="special">()</phrase> <phrase role="special">{}</phrase></code> but <code>plain
+ text</code>.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Sadly this doesn't work.
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <code>int main() {}</code>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+</article>
diff --git a/tools/quickbook/test/source_mode-1_7.quickbook b/tools/quickbook/test/source_mode-1_7.quickbook
new file mode 100644
index 0000000000..f5b9ee37fe
--- /dev/null
+++ b/tools/quickbook/test/source_mode-1_7.quickbook
@@ -0,0 +1,12 @@
+[quickbook 1.7]
+[source-mode teletype]
+[article Source Mode Test]
+
+[!c++][table [[``int main() {}``][``void foo() {}``]]]
+``Plain text...``
+
+[!c++]`int main() {}` but `plain text`.
+
+[!c++]
+* Sadly this doesn't work.
+* `int main() {}`
diff --git a/tools/quickbook/test/unit/Jamfile.v2 b/tools/quickbook/test/unit/Jamfile.v2
index ea60b90404..0b583b796b 100644
--- a/tools/quickbook/test/unit/Jamfile.v2
+++ b/tools/quickbook/test/unit/Jamfile.v2
@@ -13,6 +13,11 @@ project quickbook-unit-tests
<include>../../src
<warnings>all
<library>/boost//filesystem
+ <toolset>gcc:<cflags>-g0
+ <toolset>darwin:<cflags>-g0
+ <toolset>msvc:<cflags>/wd4709
+ <toolset>gcc:<define>BOOST_DETAIL_CONTAINER_FWD
+ <toolset>darwin:<define>BOOST_DETAIL_CONTAINER_FWD
;
run values_test.cpp ../../src/values.cpp ../../src/files.cpp ../../src/string_ref.cpp ;
@@ -20,4 +25,4 @@ run post_process_test.cpp ../../src/post_process.cpp ;
# Copied from spirit
run symbols_tests.cpp ;
-run symbols_find_null.cpp ; \ No newline at end of file
+run symbols_find_null.cpp ;
diff --git a/tools/quickbook/test/version-1_7-fail.quickbook b/tools/quickbook/test/version-1_8-fail.quickbook
index 9820b7435c..4311034ba7 100644
--- a/tools/quickbook/test/version-1_7-fail.quickbook
+++ b/tools/quickbook/test/version-1_8-fail.quickbook
@@ -1,5 +1,5 @@
[article Future version of quickbook
- [quickbook 1.7]
+ [quickbook 1.8]
]
This should fail... \ No newline at end of file
diff --git a/tools/regression/doc/index.html b/tools/regression/doc/index.html
index 1ce288ab54..799ba5df41 100644
--- a/tools/regression/doc/index.html
+++ b/tools/regression/doc/index.html
@@ -43,7 +43,7 @@
</ul>
<hr />
- <p>Revised $Date: 2010-06-26 08:30:09 -0400 (Sat, 26 Jun 2010) $</p>
+ <p>Revised $Date: 2010-06-26 05:30:09 -0700 (Sat, 26 Jun 2010) $</p>
<p>Copyright Beman Dawes 2003.</p>
diff --git a/tools/regression/doc/library_status.html b/tools/regression/doc/library_status.html
index e85d30405b..0b83ca44e7 100644
--- a/tools/regression/doc/library_status.html
+++ b/tools/regression/doc/library_status.html
@@ -459,6 +459,6 @@
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or
http://www.boost.org/LICENSE_1_0.txt)</p>
- <p>Revised $Date: 2011-10-06 11:41:40 -0400 (Thu, 06 Oct 2011) $</p>
+ <p>Revised $Date: 2011-10-06 08:41:40 -0700 (Thu, 06 Oct 2011) $</p>
</body>
</html>
diff --git a/tools/regression/src/regression.py b/tools/regression/src/regression.py
index 0976c318da..5bda7c4f7a 100644
--- a/tools/regression/src/regression.py
+++ b/tools/regression/src/regression.py
@@ -549,7 +549,7 @@ class runner:
raise
def command_show_revision(self):
- modified = '$Date: 2011-10-06 11:41:40 -0400 (Thu, 06 Oct 2011) $'
+ modified = '$Date: 2011-10-06 08:41:40 -0700 (Thu, 06 Oct 2011) $'
revision = '$Revision: 74759 $'
import re
diff --git a/tools/wave/cpp.cpp b/tools/wave/cpp.cpp
index 91270dcf49..32bdd62ba0 100644
--- a/tools/wave/cpp.cpp
+++ b/tools/wave/cpp.cpp
@@ -3,7 +3,7 @@
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
@@ -60,7 +60,7 @@ typedef boost::archive::text_oarchive oarchive;
// Include lexer specifics, import lexer names
#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
#include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
-#endif
+#endif
///////////////////////////////////////////////////////////////////////////////
// Include the grammar definitions, if these shouldn't be compiled separately
@@ -72,7 +72,7 @@ typedef boost::archive::text_oarchive oarchive;
#include <boost/wave/grammars/cpp_expression_grammar.hpp>
#include <boost/wave/grammars/cpp_predef_macros_grammar.hpp>
#include <boost/wave/grammars/cpp_defined_grammar.hpp>
-#endif
+#endif
///////////////////////////////////////////////////////////////////////////////
// Import required names
@@ -81,7 +81,6 @@ using namespace boost::spirit::classic;
using std::pair;
using std::vector;
using std::getline;
-using std::ifstream;
using std::ofstream;
using std::cout;
using std::cerr;
@@ -91,7 +90,7 @@ using std::istreambuf_iterator;
///////////////////////////////////////////////////////////////////////////////
//
-// This application uses the lex_iterator and lex_token types predefined
+// This application uses the lex_iterator and lex_token types predefined
// with the Wave library, but it is possible to use your own types.
//
// You may want to have a look at the other samples to see how this is
@@ -100,14 +99,14 @@ using std::istreambuf_iterator;
typedef boost::wave::cpplexer::lex_iterator<token_type>
lex_iterator_type;
-// The C++ preprocessor iterators shouldn't be constructed directly. They
-// are to be generated through a boost::wave::context<> object. This
-// boost::wave::context object is additionally to be used to initialize and
+// The C++ preprocessor iterators shouldn't be constructed directly. They
+// are to be generated through a boost::wave::context<> object. This
+// boost::wave::context object is additionally to be used to initialize and
// define different parameters of the actual preprocessing.
typedef boost::wave::context<
std::string::iterator, lex_iterator_type,
boost::wave::iteration_context_policies::load_file_to_string,
- trace_macro_expansion<token_type> >
+ trace_macro_expansion<token_type> >
context_type;
///////////////////////////////////////////////////////////////////////////////
@@ -138,7 +137,7 @@ int print_copyright()
"Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library",
"http://www.boost.org/",
"",
- "Copyright (c) 2001-2011 Hartmut Kaiser, Distributed under the Boost",
+ "Copyright (c) 2001-2012 Hartmut Kaiser, Distributed under the Boost",
"Software License, Version 1.0. (See accompanying file",
"LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)",
0
@@ -152,7 +151,7 @@ int print_copyright()
///////////////////////////////////////////////////////////////////////////////
// forward declarations only
-namespace cmd_line_utils
+namespace cmd_line_utils
{
class include_paths;
}
@@ -173,12 +172,12 @@ namespace fs = boost::filesystem;
///////////////////////////////////////////////////////////////////////////////
namespace cmd_line_utils {
- // Additional command line parser which interprets '@something' as an
+ // Additional command line parser which interprets '@something' as an
// option "config-file" with the value "something".
- inline pair<std::string, std::string>
+ inline pair<std::string, std::string>
at_option_parser(std::string const&s)
{
- if ('@' == s[0])
+ if ('@' == s[0])
return std::make_pair(std::string("config-file"), s.substr(1));
else
return pair<std::string, std::string>();
@@ -194,7 +193,7 @@ namespace cmd_line_utils {
bool seen_separator; // command line contains a '-I-' option
// Function which validates additional tokens from command line.
- static void
+ static void
validate(boost::any &v, vector<std::string> const &tokens)
{
if (v.empty())
@@ -208,11 +207,11 @@ namespace cmd_line_utils {
if (t == "-") {
// found -I- option, so switch behaviour
p->seen_separator = true;
- }
+ }
else if (p->seen_separator) {
// store this path as a system path
- p->syspaths.push_back(t);
- }
+ p->syspaths.push_back(t);
+ }
else {
// store this path as an user path
p->paths.push_back(t);
@@ -222,15 +221,15 @@ namespace cmd_line_utils {
// Read all options from a given config file, parse and add them to the
// given variables_map
- bool read_config_file_options(std::string const &filename,
+ bool read_config_file_options(std::string const &filename,
po::options_description const &desc, po::variables_map &vm,
bool may_fail = false)
{
- ifstream ifs(filename.c_str());
+ std::ifstream ifs(filename.c_str());
if (!ifs.is_open()) {
if (!may_fail) {
- cerr << filename
+ cerr << filename
<< ": command line warning: config file not found"
<< endl;
}
@@ -243,7 +242,7 @@ namespace cmd_line_utils {
while (std::getline(ifs, line)) {
// skip empty lines
std::string::size_type pos = line.find_first_not_of(" \t");
- if (pos == std::string::npos)
+ if (pos == std::string::npos)
continue;
// skip comment lines
@@ -294,7 +293,7 @@ namespace cmd_line_utils {
namespace boost { namespace program_options {
void validate(boost::any &v, std::vector<std::string> const &s,
- cmd_line_utils::include_paths *, long)
+ cmd_line_utils::include_paths *, long)
{
cmd_line_utils::include_paths::validate(v, s);
}
@@ -315,8 +314,8 @@ namespace {
~auto_stop_watch()
{
if (print_time) {
- outstrm << "Elapsed time: "
- << this->format_elapsed_time()
+ outstrm << "Elapsed time: "
+ << this->format_elapsed_time()
<< std::endl;
}
}
@@ -325,14 +324,14 @@ namespace {
{
print_time = print_time_;
}
-
+
private:
bool print_time;
std::ostream &outstrm;
};
///////////////////////////////////////////////////////////////////////////
- inline std::string
+ inline std::string
report_iostate_error(std::ios::iostate state)
{
BOOST_ASSERT(state & (std::ios::badbit | std::ios::failbit | std::ios::eofbit));
@@ -356,7 +355,7 @@ namespace {
// Retrieve the position of a macro definition
template <typename Context>
inline bool
- get_macro_position(Context &ctx,
+ get_macro_position(Context &ctx,
typename Context::token_type::string_type const& name,
typename Context::position_type &pos)
{
@@ -365,19 +364,19 @@ namespace {
std::vector<typename Context::token_type> parameters;
typename Context::token_sequence_type definition;
- return ctx.get_macro_definition(name, has_parameters, is_predefined,
+ return ctx.get_macro_definition(name, has_parameters, is_predefined,
pos, parameters, definition);
}
///////////////////////////////////////////////////////////////////////////
// Generate some meaningful error messages
- template <typename Exception>
- inline int
+ template <typename Exception>
+ inline int
report_error_message(Exception const &e)
{
// default error reporting
- cerr
- << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
+ cerr
+ << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
<< ": " << e.description() << endl;
// errors count as one
@@ -386,7 +385,7 @@ namespace {
}
template <typename Context>
- inline int
+ inline int
report_error_message(Context &ctx, boost::wave::cpp_exception const &e)
{
// default error reporting
@@ -399,16 +398,16 @@ namespace {
// report the point of the initial macro definition
typename Context::position_type pos;
if (get_macro_position(ctx, e.get_related_name(), pos)) {
- cerr
- << pos << ": "
+ cerr
+ << pos << ": "
<< preprocess_exception::severity_text(e.get_severity())
- << ": this is the location of the previous definition."
+ << ": this is the location of the previous definition."
<< endl;
}
else {
- cerr
- << e.file_name() << ":" << e.line_no() << ":"
- << e.column_no() << ": "
+ cerr
+ << e.file_name() << ":" << e.line_no() << ":"
+ << e.column_no() << ": "
<< preprocess_exception::severity_text(e.get_severity())
<< ": not able to retrieve the location of the previous "
<< "definition." << endl;
@@ -425,7 +424,7 @@ namespace {
///////////////////////////////////////////////////////////////////////////
// Read one logical line of text
- inline bool
+ inline bool
read_a_line (std::istream &instream, std::string &instring)
{
bool eol = true;
@@ -436,7 +435,7 @@ namespace {
return false; // nothing to do
eol = true;
- if (line.find_last_of('\\') == line.size()-1)
+ if (line.find_last_of('\\') == line.size()-1)
eol = false;
instring += line + '\n';
@@ -447,7 +446,7 @@ namespace {
///////////////////////////////////////////////////////////////////////////
// Load and save the internal tables of the wave::context object
template <typename Context>
- inline void
+ inline void
load_state(po::variables_map const &vm, Context &ctx)
{
#if BOOST_WAVE_SERIALIZATION != 0
@@ -455,7 +454,7 @@ namespace {
if (vm.count("state") > 0) {
fs::path state_file (
boost::wave::util::create_path(vm["state"].as<std::string>()));
- if (state_file == "-")
+ if (state_file == "-")
state_file = boost::wave::util::create_path("wave.state");
std::ios::openmode mode = std::ios::in;
@@ -463,12 +462,12 @@ namespace {
#if BOOST_WAVE_BINARY_SERIALIZATION != 0
mode = (std::ios::openmode)(mode | std::ios::binary);
#endif
- ifstream ifs (state_file.string().c_str(), mode);
+ std::ifstream ifs (state_file.string().c_str(), mode);
if (ifs.is_open()) {
using namespace boost::serialization;
iarchive ia(ifs);
std::string version;
-
+
ia >> make_nvp("version", version); // load version
if (version == CPP_VERSION_FULL_STR)
ia >> make_nvp("state", ctx); // load the internal tables from disc
@@ -481,18 +480,18 @@ namespace {
}
}
catch (boost::archive::archive_exception const& e) {
- cerr << "wave: error while loading state: "
+ cerr << "wave: error while loading state: "
<< e.what() << endl;
}
catch (boost::wave::preprocess_exception const& e) {
- cerr << "wave: error while loading state: "
+ cerr << "wave: error while loading state: "
<< e.description() << endl;
}
#endif
}
template <typename Context>
- inline void
+ inline void
save_state(po::variables_map const &vm, Context const &ctx)
{
#if BOOST_WAVE_SERIALIZATION != 0
@@ -500,7 +499,7 @@ namespace {
if (vm.count("state") > 0) {
fs::path state_file (boost::wave::util::create_path(
vm["state"].as<std::string>()));
- if (state_file == "-")
+ if (state_file == "-")
state_file = boost::wave::util::create_path("wave.state");
std::ios::openmode mode = std::ios::out;
@@ -510,7 +509,7 @@ namespace {
#endif
ofstream ofs(state_file.string().c_str(), mode);
if (!ofs.is_open()) {
- cerr << "wave: could not open state file for writing: "
+ cerr << "wave: could not open state file for writing: "
<< state_file.string() << endl;
// this is non-fatal
}
@@ -524,7 +523,7 @@ namespace {
}
}
catch (boost::archive::archive_exception const& e) {
- cerr << "wave: error while writing state: "
+ cerr << "wave: error while writing state: "
<< e.what() << endl;
}
#endif
@@ -540,10 +539,11 @@ namespace {
if (macronames_file != "-") {
macronames_file = boost::wave::util::complete_path(macronames_file);
- fs::create_directories(boost::wave::util::branch_path(macronames_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(macronames_file));
macronames_out.open(macronames_file.string().c_str());
if (!macronames_out.is_open()) {
- cerr << "wave: could not open file for macro name listing: "
+ cerr << "wave: could not open file for macro name listing: "
<< macronames_file.string() << endl;
return false;
}
@@ -557,7 +557,7 @@ namespace {
// simply list all defined macros and its definitions
typedef context_type::const_name_iterator name_iterator;
name_iterator end = ctx.macro_names_end();
- for (name_iterator it = ctx.macro_names_begin(); it != end; ++it)
+ for (name_iterator it = ctx.macro_names_begin(); it != end; ++it)
{
typedef std::vector<context_type::token_type> parameters_type;
@@ -609,10 +609,11 @@ namespace {
if (macrocounts_file != "-") {
macrocounts_file = boost::wave::util::complete_path(macrocounts_file);
- fs::create_directories(boost::wave::util::branch_path(macrocounts_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(macrocounts_file));
macrocounts_out.open(macrocounts_file.string().c_str());
if (!macrocounts_out.is_open()) {
- cerr << "wave: could not open file for macro invocation count listing: "
+ cerr << "wave: could not open file for macro invocation count listing: "
<< macrocounts_file.string() << endl;
return false;
}
@@ -635,13 +636,31 @@ namespace {
return true;
}
-///////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+ // read all of a file into a string
+ std::string read_entire_file(std::istream& instream)
+ {
+ std::string content;
+
+ instream.unsetf(std::ios::skipws);
+
+#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
+ // this is known to be very slow for large files on some systems
+ copy (std::istream_iterator<char>(instream),
+ std::istream_iterator<char>(),
+ std::inserter(content, content.end()));
+#else
+ content = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
+ std::istreambuf_iterator<char>());
+#endif
+ return content;
+ }
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
// do the actual preprocessing
-int
-do_actual_work (std::string file_name, std::istream &instream,
+int
+do_actual_work (std::string file_name, std::istream &instream,
po::variables_map const &vm, bool input_is_stdin)
{
// current file position is saved for exception handling
@@ -654,20 +673,10 @@ int error_count = 0;
std::string instring;
instream.unsetf(std::ios::skipws);
+ if (!input_is_stdin)
+ instring = read_entire_file(instream);
- if (!input_is_stdin) {
-#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
- // this is known to be very slow for large files on some systems
- copy (std::istream_iterator<char>(instream),
- std::istream_iterator<char>(),
- std::inserter(instring, instring.end()));
-#else
- instring = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
- std::istreambuf_iterator<char>());
-#endif
- }
-
- // The preprocessing of the input stream is done on the fly behind the
+ // The preprocessing of the input stream is done on the fly behind the
// scenes during iteration over the context_type::iterator_type stream.
std::ofstream output;
std::ofstream traceout;
@@ -682,10 +691,11 @@ int error_count = 0;
vm["traceto"].as<std::string>()));
if (trace_file != "-") {
- fs::create_directories(boost::wave::util::branch_path(trace_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(trace_file));
traceout.open(trace_file.string().c_str());
if (!traceout.is_open()) {
- cerr << "wave: could not open trace file: " << trace_file
+ cerr << "wave: could not open trace file: " << trace_file
<< endl;
return -1;
}
@@ -701,15 +711,16 @@ int error_count = 0;
// Open the stream where to output the list of included file names
if (vm.count("listincludes")) {
- // try to open the file, where to put the include list
+ // try to open the file, where to put the include list
fs::path includes_file(boost::wave::util::create_path(
vm["listincludes"].as<std::string>()));
if (includes_file != "-") {
- fs::create_directories(boost::wave::util::branch_path(includes_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(includes_file));
includelistout.open(includes_file.string().c_str());
if (!includelistout.is_open()) {
- cerr << "wave: could not open include list file: "
+ cerr << "wave: could not open include list file: "
<< includes_file.string() << endl;
return -1;
}
@@ -726,15 +737,16 @@ int error_count = 0;
// Open the stream where to output the list of included file names
if (vm.count("listguards")) {
- // try to open the file, where to put the include list
+ // try to open the file, where to put the include list
fs::path listguards_file(boost::wave::util::create_path(
vm["listguards"].as<std::string>()));
if (listguards_file != "-") {
- fs::create_directories(boost::wave::util::branch_path(listguards_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(listguards_file));
listguardsout.open(listguards_file.string().c_str());
if (!listguardsout.is_open()) {
- cerr << "wave: could not open include guard list file: "
+ cerr << "wave: could not open include guard list file: "
<< listguards_file.string() << endl;
return -1;
}
@@ -775,50 +787,67 @@ int error_count = 0;
break;
default:
- cerr << "wave: bogus preserve whitespace option value: "
+ cerr << "wave: bogus preserve whitespace option value: "
<< preserve << ", should be 0, 1, 2, or 3" << endl;
return -1;
}
}
- // Since the #pragma wave system() directive may cause a potential security
+ // Since the #pragma wave system() directive may cause a potential security
// threat, it has to be enabled explicitly by --extended or -x
bool enable_system_command = false;
- if (vm.count("extended"))
+ if (vm.count("extended"))
enable_system_command = true;
- // This this the central piece of the Wave library, it provides you with
+ // This this the central piece of the Wave library, it provides you with
// the iterators to get the preprocessed tokens and allows to configure
// the preprocessing stage in advance.
bool allow_output = true; // will be manipulated from inside the hooks object
std::string default_outfile; // will be used from inside the hooks object
- trace_macro_expansion<token_type> hooks(preserve_whitespace,
- preserve_bol_whitespace, output, traceout, includelistout,
- listguardsout, enable_trace, enable_system_command, allow_output,
+ trace_macro_expansion<token_type> hooks(preserve_whitespace,
+ preserve_bol_whitespace, output, traceout, includelistout,
+ listguardsout, enable_trace, enable_system_command, allow_output,
default_outfile);
// enable macro invocation count, if appropriate
- if (vm.count("macrocounts"))
+ if (vm.count("macrocounts"))
hooks.enable_macro_counting();
+ // check, if we have a license file to prepend
+ std::string license;
+
+ if (vm.count ("license")) {
+ // try to open the file, where to put the preprocessed output
+ std::string license_file(vm["license"].as<std::string>());
+ std::ifstream license_stream(license_file.c_str());
+
+ if (!license_stream.is_open()) {
+ cerr << "wave: could not open specified license file: "
+ << license_file << endl;
+ return -1;
+ }
+ license = read_entire_file(license_stream);
+ hooks.set_license_info(license);
+ }
+
context_type ctx (instring.begin(), instring.end(), file_name.c_str(), hooks);
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
// enable C99 mode, if appropriate (implies variadics)
if (vm.count("c99")) {
#if BOOST_WAVE_SUPPORT_CPP0X != 0
- if (vm.count("c++0x")) {
+ if (vm.count("c++11")) {
cerr << "wave: multiple language options specified: --c99 "
- "and --c++0x" << endl;
+ "and --c++11" << endl;
return -1;
}
#endif
ctx.set_language(
boost::wave::language_support(
- boost::wave::support_c99
- | boost::wave::support_option_convert_trigraphs
- | boost::wave::support_option_emit_line_directives
+ boost::wave::support_c99
+ | boost::wave::support_option_convert_trigraphs
+ | boost::wave::support_option_emit_line_directives
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
| boost::wave::support_option_include_guard_detection
#endif
@@ -834,18 +863,18 @@ int error_count = 0;
}
#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
#if BOOST_WAVE_SUPPORT_CPP0X != 0
- if (vm.count("c++0x")) {
+ if (vm.count("c++11")) {
if (vm.count("c99")) {
cerr << "wave: multiple language options specified: --c99 "
- "and --c++0x" << endl;
+ "and --c++11" << endl;
return -1;
}
ctx.set_language(
boost::wave::language_support(
boost::wave::support_cpp0x
- | boost::wave::support_option_convert_trigraphs
- | boost::wave::support_option_long_long
- | boost::wave::support_option_emit_line_directives
+ | boost::wave::support_option_convert_trigraphs
+ | boost::wave::support_option_long_long
+ | boost::wave::support_option_emit_line_directives
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
| boost::wave::support_option_include_guard_detection
#endif
@@ -882,15 +911,15 @@ int error_count = 0;
if (vm.count("line")) {
int lineopt = vm["line"].as<int>();
if (0 != lineopt && 1 != lineopt && 2 != lineopt) {
- cerr << "wave: bogus value for --line command line option: "
+ cerr << "wave: bogus value for --line command line option: "
<< lineopt << endl;
return -1;
}
ctx.set_language(
- boost::wave::enable_emit_line_directives(ctx.get_language(),
+ boost::wave::enable_emit_line_directives(ctx.get_language(),
lineopt != 0));
- if (2 == lineopt)
+ if (2 == lineopt)
ctx.get_hooks().enable_relative_names_in_line_directives(true);
}
@@ -898,12 +927,12 @@ int error_count = 0;
if (vm.count("disambiguate")) {
int disambiguateopt = vm["disambiguate"].as<int>();
if (0 != disambiguateopt && 1 != disambiguateopt) {
- cerr << "wave: bogus value for --disambiguate command line option: "
+ cerr << "wave: bogus value for --disambiguate command line option: "
<< disambiguateopt << endl;
return -1;
}
ctx.set_language(
- boost::wave::enable_insert_whitespace(ctx.get_language(),
+ boost::wave::enable_insert_whitespace(ctx.get_language(),
disambiguateopt != 0));
}
@@ -912,7 +941,7 @@ int error_count = 0;
vector<std::string> syspaths = vm["sysinclude"].as<vector<std::string> >();
vector<std::string>::const_iterator end = syspaths.end();
- for (vector<std::string>::const_iterator cit = syspaths.begin();
+ for (vector<std::string>::const_iterator cit = syspaths.begin();
cit != end; ++cit)
{
ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*cit).c_str());
@@ -921,46 +950,46 @@ int error_count = 0;
// add include directories to the include search paths
if (vm.count("include")) {
- cmd_line_utils::include_paths const &ip =
+ cmd_line_utils::include_paths const &ip =
vm["include"].as<cmd_line_utils::include_paths>();
vector<std::string>::const_iterator end = ip.paths.end();
- for (vector<std::string>::const_iterator cit = ip.paths.begin();
+ for (vector<std::string>::const_iterator cit = ip.paths.begin();
cit != end; ++cit)
{
ctx.add_include_path(cmd_line_utils::trim_quotes(*cit).c_str());
}
// if -I- was given on the command line, this has to be propagated
- if (ip.seen_separator)
+ if (ip.seen_separator)
ctx.set_sysinclude_delimiter();
// add system include directories to the include path
vector<std::string>::const_iterator sysend = ip.syspaths.end();
- for (vector<std::string>::const_iterator syscit = ip.syspaths.begin();
+ for (vector<std::string>::const_iterator syscit = ip.syspaths.begin();
syscit != sysend; ++syscit)
{
ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*syscit).c_str());
}
}
- // add additional defined macros
+ // add additional defined macros
if (vm.count("define")) {
vector<std::string> const &macros = vm["define"].as<vector<std::string> >();
vector<std::string>::const_iterator end = macros.end();
- for (vector<std::string>::const_iterator cit = macros.begin();
+ for (vector<std::string>::const_iterator cit = macros.begin();
cit != end; ++cit)
{
ctx.add_macro_definition(*cit);
}
}
- // add additional predefined macros
+ // add additional predefined macros
if (vm.count("predefine")) {
- vector<std::string> const &predefmacros =
+ vector<std::string> const &predefmacros =
vm["predefine"].as<vector<std::string> >();
vector<std::string>::const_iterator end = predefmacros.end();
- for (vector<std::string>::const_iterator cit = predefmacros.begin();
+ for (vector<std::string>::const_iterator cit = predefmacros.begin();
cit != end; ++cit)
{
ctx.add_macro_definition(*cit, true);
@@ -969,10 +998,10 @@ int error_count = 0;
// undefine specified macros
if (vm.count("undefine")) {
- vector<std::string> const &undefmacros =
+ vector<std::string> const &undefmacros =
vm["undefine"].as<vector<std::string> >();
vector<std::string>::const_iterator end = undefmacros.end();
- for (vector<std::string>::const_iterator cit = undefmacros.begin();
+ for (vector<std::string>::const_iterator cit = undefmacros.begin();
cit != end; ++cit)
{
ctx.remove_macro_definition(*cit, true);
@@ -982,10 +1011,10 @@ int error_count = 0;
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
// suppress expansion of specified macros
if (vm.count("noexpand")) {
- vector<std::string> const &noexpandmacros =
+ vector<std::string> const &noexpandmacros =
vm["noexpand"].as<vector<std::string> >();
vector<std::string>::const_iterator end = noexpandmacros.end();
- for (vector<std::string>::const_iterator cit = noexpandmacros.begin();
+ for (vector<std::string>::const_iterator cit = noexpandmacros.begin();
cit != end; ++cit)
{
ctx.get_hooks().add_noexpandmacro(*cit);
@@ -997,7 +1026,7 @@ int error_count = 0;
if (vm.count("nesting")) {
int max_depth = vm["nesting"].as<int>();
if (max_depth < 1 || max_depth > 100000) {
- cerr << "wave: bogus maximal include nesting depth: "
+ cerr << "wave: bogus maximal include nesting depth: "
<< max_depth << endl;
return -1;
}
@@ -1016,13 +1045,16 @@ int error_count = 0;
}
else {
out_file = boost::wave::util::complete_path(out_file);
- fs::create_directories(boost::wave::util::branch_path(out_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(out_file));
output.open(out_file.string().c_str());
if (!output.is_open()) {
- cerr << "wave: could not open output file: "
+ cerr << "wave: could not open output file: "
<< out_file.string() << endl;
return -1;
}
+ if (!license.empty())
+ output << license;
default_outfile = out_file.string();
}
}
@@ -1031,22 +1063,25 @@ int error_count = 0;
fs::path out_file (boost::wave::util::create_path(file_name));
std::string basename (boost::wave::util::leaf(out_file));
std::string::size_type pos = basename.find_last_of(".");
-
+
if (std::string::npos != pos)
basename = basename.substr(0, pos);
out_file = boost::wave::util::branch_path(out_file) / (basename + ".i");
- fs::create_directories(boost::wave::util::branch_path(out_file));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(out_file));
output.open(out_file.string().c_str());
if (!output.is_open()) {
- cerr << "wave: could not open output file: "
+ cerr << "wave: could not open output file: "
<< out_file.string() << endl;
return -1;
}
+ if (!license.empty())
+ output << license;
default_outfile = out_file.string();
}
- // we assume the session to be interactive if input is stdin and output is
+ // we assume the session to be interactive if input is stdin and output is
// stdout and the output is not inhibited
bool is_interactive = input_is_stdin && !output.is_open() && allow_output;
@@ -1060,15 +1095,15 @@ int error_count = 0;
context_type::iterator_type first = ctx.begin();
context_type::iterator_type last = ctx.end();
- // preprocess the required include files
+ // preprocess the required include files
if (vm.count("forceinclude")) {
// add the filenames to force as include files in _reverse_ order
// the second parameter 'is_last' of the force_include function should
// be set to true for the last (first given) file.
- vector<std::string> const &force =
- vm["forceinclude"].as<vector<std::string> >();
- vector<std::string>::const_reverse_iterator rend = force.rend();
- for (vector<std::string>::const_reverse_iterator cit = force.rbegin();
+ std::vector<std::string> const &force =
+ vm["forceinclude"].as<std::vector<std::string> >();
+ std::vector<std::string>::const_reverse_iterator rend = force.rend();
+ for (std::vector<std::string>::const_reverse_iterator cit = force.rbegin();
cit != rend; /**/)
{
std::string filename(*cit);
@@ -1091,11 +1126,11 @@ int error_count = 0;
// loop over the input lines if reading from stdin, otherwise this loop
// will be executed once
do {
- // loop over all generated tokens outputting the generated text
+ // loop over all generated tokens outputting the generated text
bool finished = false;
if (input_is_stdin) {
- if (is_interactive)
+ if (is_interactive)
cout << ">>> "; // prompt if is interactive
// read next line and continue
@@ -1149,8 +1184,8 @@ int error_count = 0;
}
catch (boost::wave::cpplexer::lexing_exception const &e) {
// some preprocessing error
- if (is_interactive ||
- boost::wave::cpplexer::is_recoverable(e))
+ if (is_interactive ||
+ boost::wave::cpplexer::is_recoverable(e))
{
error_count += report_error_message(e);
need_to_advanve = true; // advance to the next token
@@ -1162,7 +1197,7 @@ int error_count = 0;
} while (!finished);
} while (input_is_stdin);
- if (is_interactive)
+ if (is_interactive)
save_state(vm, ctx); // write the internal tables to disc
// list all defined macros at the end of the preprocessing
@@ -1187,7 +1222,7 @@ int error_count = 0;
}
catch (std::exception const &e) {
// use last recognized token to retrieve the error position
- cerr
+ cerr
<< current_position << ": "
<< "exception caught: " << e.what()
<< endl;
@@ -1195,7 +1230,7 @@ int error_count = 0;
}
catch (...) {
// use last recognized token to retrieve the error position
- cerr
+ cerr
<< current_position << ": "
<< "unexpected exception caught." << endl;
return 4;
@@ -1211,7 +1246,7 @@ main (int argc, char *argv[])
// test Wave compilation configuration
if (!BOOST_WAVE_TEST_CONFIGURATION()) {
cout << "wave: warning: the library this application was linked against was compiled "
- << endl
+ << endl
<< " using a different configuration (see wave_config.hpp)."
<< endl;
}
@@ -1225,7 +1260,7 @@ main (int argc, char *argv[])
("help,h", "print out program usage (this message)")
("version,v", "print the version number")
("copyright", "print out the copyright statement")
- ("config-file", po::value<vector<std::string> >()->composing(),
+ ("config-file", po::value<vector<std::string> >()->composing(),
"specify a config file (alternatively: @filepath)")
;
@@ -1233,35 +1268,37 @@ main (int argc, char *argv[])
po::options_description desc_generic ("Options allowed additionally in a config file");
desc_generic.add_options()
- ("output,o", po::value<std::string>(),
+ ("output,o", po::value<std::string>(),
"specify a file [arg] to use for output instead of stdout or "
"disable output [-]")
- ("autooutput,E",
+ ("autooutput,E",
"output goes into a file named <input_basename>.i")
- ("include,I", po::value<cmd_line_utils::include_paths>()->composing(),
+ ("license", po::value<std::string>(),
+ "prepend the content of the specified file to each created file")
+ ("include,I", po::value<cmd_line_utils::include_paths>()->composing(),
"specify an additional include directory")
- ("sysinclude,S", po::value<vector<std::string> >()->composing(),
+ ("sysinclude,S", po::value<vector<std::string> >()->composing(),
"specify an additional system include directory")
- ("forceinclude,F", po::value<vector<std::string> >()->composing(),
+ ("forceinclude,F", po::value<std::vector<std::string> >()->composing(),
"force inclusion of the given file")
- ("define,D", po::value<vector<std::string> >()->composing(),
+ ("define,D", po::value<std::vector<std::string> >()->composing(),
"specify a macro to define (as macro[=[value]])")
- ("predefine,P", po::value<vector<std::string> >()->composing(),
+ ("predefine,P", po::value<std::vector<std::string> >()->composing(),
"specify a macro to predefine (as macro[=[value]])")
- ("undefine,U", po::value<vector<std::string> >()->composing(),
+ ("undefine,U", po::value<std::vector<std::string> >()->composing(),
"specify a macro to undefine")
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
- ("noexpand,N", po::value<vector<std::string> >()->composing(),
+ ("noexpand,N", po::value<std::vector<std::string> >()->composing(),
"specify a macro name, which should not be expanded")
#endif
- ("nesting,n", po::value<int>(),
+ ("nesting,n", po::value<int>(),
"specify a new maximal include nesting depth")
;
po::options_description desc_ext ("Extended options (allowed everywhere)");
desc_ext.add_options()
- ("traceto,t", po::value<std::string>(),
+ ("traceto,t", po::value<std::string>(),
"output macro expansion tracing information to a file [arg] "
"or to stderr [-]")
("timer", "output overall elapsed computing time to stderr")
@@ -1269,29 +1306,29 @@ main (int argc, char *argv[])
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
("variadics", "enable certain C99 extensions in C++ mode")
("c99", "enable C99 mode (implies --variadics)")
-#endif
+#endif
#if BOOST_WAVE_SUPPORT_CPP0X != 0
- ("c++0x", "enable C++0x mode (implies --variadics and --long_long)")
-#endif
- ("listincludes,l", po::value<std::string>(),
+ ("c++11", "enable C++11 mode (implies --variadics and --long_long)")
+#endif
+ ("listincludes,l", po::value<std::string>(),
"list names of included files to a file [arg] or to stdout [-]")
- ("macronames,m", po::value<std::string>(),
+ ("macronames,m", po::value<std::string>(),
"list all defined macros to a file [arg] or to stdout [-]")
- ("macrocounts,c", po::value<std::string>(),
+ ("macrocounts,c", po::value<std::string>(),
"list macro invocation counts to a file [arg] or to stdout [-]")
- ("preserve,p", po::value<int>()->default_value(0),
+ ("preserve,p", po::value<int>()->default_value(0),
"preserve whitespace\n"
"0: no whitespace is preserved (default),\n"
- "1: begin of line whitespace is preserved,\n"
- "2: comments and begin of line whitespace is preserved,\n"
+ "1: begin of line whitespace is preserved,\n"
+ "2: comments and begin of line whitespace is preserved,\n"
"3: all whitespace is preserved")
- ("line,L", po::value<int>()->default_value(1),
+ ("line,L", po::value<int>()->default_value(1),
"control the generation of #line directives\n"
"0: no #line directives are generated,\n"
"1: #line directives will be emitted (default),\n"
"2: #line directives will be emitted using relative\n"
" filenames")
- ("disambiguate", po::value<int>()->default_value(1),
+ ("disambiguate", po::value<int>()->default_value(1),
"control whitespace insertion to disambiguate\n"
"consecutive tokens\n"
"0: no additional whitespace is generated,\n"
@@ -1299,12 +1336,12 @@ main (int argc, char *argv[])
("extended,x", "enable the #pragma wave system() directive")
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
("noguard,G", "disable include guard detection")
- ("listguards,g", po::value<std::string>(),
+ ("listguards,g", po::value<std::string>(),
"list names of files flagged as 'include once' to a file [arg] "
"or to stdout [-]")
#endif
#if BOOST_WAVE_SERIALIZATION != 0
- ("state,s", po::value<std::string>(),
+ ("state,s", po::value<std::string>(),
"load and save state information from/to the given file [arg] "
"or 'wave.state' [-] (interactive mode only)")
#endif
@@ -1320,29 +1357,29 @@ main (int argc, char *argv[])
// parse command line and store results
using namespace boost::program_options::command_line_style;
- po::parsed_options opts(po::parse_command_line(argc, argv,
+ po::parsed_options opts(po::parse_command_line(argc, argv,
desc_overall_cmdline, unix_style, cmd_line_utils::at_option_parser));
po::variables_map vm;
po::store(opts, vm);
po::notify(vm);
-// // Try to find a wave.cfg in the same directory as the executable was
+// // Try to find a wave.cfg in the same directory as the executable was
// // started from. If this exists, treat it as a wave config file
// fs::path filename(argv[0]);
-//
+//
// filename = filename.branch_path() / "wave.cfg";
-// cmd_line_utils::read_config_file_options(filename.string(),
+// cmd_line_utils::read_config_file_options(filename.string(),
// desc_overall_cfgfile, vm, true);
// extract the arguments from the parsed command line
vector<po::option> arguments;
- std::remove_copy_if(opts.options.begin(), opts.options.end(),
+ std::remove_copy_if(opts.options.begin(), opts.options.end(),
back_inserter(arguments), cmd_line_utils::is_argument());
- // try to find a config file somewhere up the filesystem hierarchy
- // starting with the input file path. This allows to use a general wave.cfg
+ // try to find a config file somewhere up the filesystem hierarchy
+ // starting with the input file path. This allows to use a general wave.cfg
// file for all files in a certain project.
if (arguments.size() > 0 && arguments[0].value[0] != "-") {
// construct full path of input file
@@ -1351,12 +1388,12 @@ main (int argc, char *argv[])
// chop of file name
input_dir = boost::wave::util::branch_path(
- boost::wave::util::normalize(input_dir));
+ boost::wave::util::normalize(input_dir));
- // walk up the hierarchy, trying to find a file wave.cfg
+ // walk up the hierarchy, trying to find a file wave.cfg
while (!input_dir.empty()) {
fs::path filename = input_dir / "wave.cfg";
- if (cmd_line_utils::read_config_file_options(filename.string(),
+ if (cmd_line_utils::read_config_file_options(filename.string(),
desc_overall_cfgfile, vm, true))
{
break; // break on the first cfg file found
@@ -1365,22 +1402,22 @@ main (int argc, char *argv[])
}
}
- // if there is specified at least one config file, parse it and add the
+ // if there is specified at least one config file, parse it and add the
// options to the main variables_map
if (vm.count("config-file")) {
- vector<std::string> const &cfg_files =
+ vector<std::string> const &cfg_files =
vm["config-file"].as<vector<std::string> >();
vector<std::string>::const_iterator end = cfg_files.end();
- for (vector<std::string>::const_iterator cit = cfg_files.begin();
+ for (vector<std::string>::const_iterator cit = cfg_files.begin();
cit != end; ++cit)
{
// parse a single config file and store the results
- cmd_line_utils::read_config_file_options(*cit,
+ cmd_line_utils::read_config_file_options(*cit,
desc_overall_cfgfile, vm);
}
}
- // ... act as required
+ // ... act as required
if (vm.count("help")) {
po::options_description desc_help (
"Usage: wave [options] [@config-file(s)] [file]");
@@ -1401,7 +1438,7 @@ main (int argc, char *argv[])
// if there is no input file given, then take input from stdin
if (0 == arguments.size() || 0 == arguments[0].value.size() ||
- arguments[0].value[0] == "-")
+ arguments[0].value[0] == "-")
{
// preprocess the given input from stdin
return do_actual_work("<stdin>", std::cin, vm, true);
@@ -1414,7 +1451,7 @@ main (int argc, char *argv[])
}
std::string file_name(arguments[0].value[0]);
- ifstream instream(file_name.c_str());
+ std::ifstream instream(file_name.c_str());
// preprocess the given input file
if (!instream.is_open()) {
diff --git a/tools/wave/cpp.hpp b/tools/wave/cpp.hpp
index d92dcc8ded..f2253f3c28 100644
--- a/tools/wave/cpp.hpp
+++ b/tools/wave/cpp.hpp
@@ -3,7 +3,7 @@
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
diff --git a/tools/wave/cpp_config.hpp b/tools/wave/cpp_config.hpp
index aed8630855..e6e4f63e2b 100644
--- a/tools/wave/cpp_config.hpp
+++ b/tools/wave/cpp_config.hpp
@@ -4,7 +4,7 @@
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
diff --git a/tools/wave/cpp_version.hpp b/tools/wave/cpp_version.hpp
index 5ce2ac1f1e..43330c2c9d 100644
--- a/tools/wave/cpp_version.hpp
+++ b/tools/wave/cpp_version.hpp
@@ -2,7 +2,7 @@
Boost.Wave: A Standard compliant C++ preprocessor library
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
@@ -19,7 +19,7 @@
#define CPP_VERSION_FULL_STR BOOST_PP_STRINGIZE(CPP_VERSION_FULL)
-#define CPP_VERSION_DATE 20110507L
-#define CPP_VERSION_DATE_STR "20110507"
+#define CPP_VERSION_DATE 20120523L
+#define CPP_VERSION_DATE_STR "20120523"
#endif // !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED)
diff --git a/tools/wave/stop_watch.hpp b/tools/wave/stop_watch.hpp
index 2342ccc903..e3285466e3 100644
--- a/tools/wave/stop_watch.hpp
+++ b/tools/wave/stop_watch.hpp
@@ -2,7 +2,7 @@
Boost.Wave: A Standard compliant C++ preprocessor library
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
diff --git a/tools/wave/trace_macro_expansion.hpp b/tools/wave/trace_macro_expansion.hpp
index 7679a2edb6..a6e7c31526 100644
--- a/tools/wave/trace_macro_expansion.hpp
+++ b/tools/wave/trace_macro_expansion.hpp
@@ -2,7 +2,7 @@
Boost.Wave: A Standard compliant C++ preprocessor library
http://www.boost.org/
- Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost
+ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
@@ -62,7 +62,7 @@ enum trace_flags {
///////////////////////////////////////////////////////////////////////////////
//
-// Special error thrown whenever the #pragma wave system() directive is
+// Special error thrown whenever the #pragma wave system() directive is
// disabled
//
///////////////////////////////////////////////////////////////////////////////
@@ -71,15 +71,15 @@ class bad_pragma_exception :
{
public:
enum error_code {
- pragma_system_not_enabled =
+ pragma_system_not_enabled =
boost::wave::preprocess_exception::last_error_number + 1,
pragma_mismatched_push_pop,
};
- bad_pragma_exception(char const *what_, error_code code, int line_,
- int column_, char const *filename_) throw()
- : boost::wave::preprocess_exception(what_,
- (boost::wave::preprocess_exception::error_code)code, line_,
+ bad_pragma_exception(char const *what_, error_code code, int line_,
+ int column_, char const *filename_) throw()
+ : boost::wave::preprocess_exception(what_,
+ (boost::wave::preprocess_exception::error_code)code, line_,
column_, filename_)
{
}
@@ -128,10 +128,10 @@ public:
};
///////////////////////////////////////////////////////////////////////////////
-//
+//
// The trace_macro_expansion policy is used to trace the macro expansion of
// macros whenever it is requested from inside the input stream to preprocess
-// through the '#pragma wave_option(trace: enable)' directive. The macro
+// through the '#pragma wave_option(trace: enable)' directive. The macro
// tracing is disabled with the help of a '#pragma wave_option(trace: disable)'
// directive.
//
@@ -148,13 +148,13 @@ class trace_macro_expansion
public:
trace_macro_expansion(
bool preserve_whitespace_, bool preserve_bol_whitespace_,
- std::ofstream &output_, std::ostream &tracestrm_,
- std::ostream &includestrm_, std::ostream &guardstrm_,
- trace_flags flags_, bool enable_system_command_,
+ std::ofstream &output_, std::ostream &tracestrm_,
+ std::ostream &includestrm_, std::ostream &guardstrm_,
+ trace_flags flags_, bool enable_system_command_,
bool& generate_output_, std::string const& default_outfile_)
- : outputstrm(output_), tracestrm(tracestrm_),
- includestrm(includestrm_), guardstrm(guardstrm_),
- level(0), flags(flags_), logging_flags(trace_nothing),
+ : outputstrm(output_), tracestrm(tracestrm_),
+ includestrm(includestrm_), guardstrm(guardstrm_),
+ level(0), flags(flags_), logging_flags(trace_nothing),
enable_system_command(enable_system_command_),
preserve_whitespace(preserve_whitespace_),
preserve_bol_whitespace(preserve_bol_whitespace_),
@@ -167,9 +167,9 @@ public:
{
}
- void enable_macro_counting()
- {
- logging_flags = trace_flags(logging_flags | trace_macro_counts);
+ void enable_macro_counting()
+ {
+ logging_flags = trace_flags(logging_flags | trace_macro_counts);
}
std::map<std::string, std::size_t> const& get_macro_counts() const
{
@@ -191,34 +191,39 @@ public:
noexpandmacros.insert(name);
}
+ void set_license_info(std::string const& info)
+ {
+ license_info = info;
+ }
+
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'expanding_function_like_macro' is called whenever a
+ //
+ // The function 'expanding_function_like_macro' is called whenever a
// function-like macro is to be expanded.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'macrodef' marks the position, where the macro to expand
+ // The parameter 'macrodef' marks the position, where the macro to expand
// is defined.
//
// The parameter 'formal_args' holds the formal arguments used during the
// definition of the macro.
//
- // The parameter 'definition' holds the macro definition for the macro to
+ // The parameter 'definition' holds the macro definition for the macro to
// trace.
//
// The parameter 'macro_call' marks the position, where this macro invoked.
//
- // The parameter 'arguments' holds the macro arguments used during the
+ // The parameter 'arguments' holds the macro arguments used during the
// invocation of the macro
//
- // The parameters 'seqstart' and 'seqend' point into the input token
+ // The parameters 'seqstart' and 'seqend' point into the input token
// stream allowing to access the whole token sequence comprising the macro
// invocation (starting with the opening parenthesis and ending after the
// closing one).
//
- // The return value defines whether the corresponding macro will be
+ // The return value defines whether the corresponding macro will be
// expanded (return false) or will be copied to the output (return true).
// Note: the whole argument list is copied unchanged to the output as well
// without any further processing.
@@ -228,24 +233,24 @@ public:
// old signature
template <typename ContainerT>
void expanding_function_like_macro(
- TokenT const &macrodef, std::vector<TokenT> const &formal_args,
+ TokenT const &macrodef, std::vector<TokenT> const &formal_args,
ContainerT const &definition,
- TokenT const &macrocall, std::vector<ContainerT> const &arguments)
+ TokenT const &macrocall, std::vector<ContainerT> const &arguments)
{
if (enabled_macro_counting())
count_invocation(macrodef.get_value().c_str());
- if (!enabled_macro_tracing())
+ if (!enabled_macro_tracing())
return;
#else
// new signature
template <typename ContextT, typename ContainerT, typename IteratorT>
- bool
+ bool
expanding_function_like_macro(ContextT const& ctx,
- TokenT const &macrodef, std::vector<TokenT> const &formal_args,
+ TokenT const &macrodef, std::vector<TokenT> const &formal_args,
ContainerT const &definition,
TokenT const &macrocall, std::vector<ContainerT> const &arguments,
- IteratorT const& seqstart, IteratorT const& seqend)
+ IteratorT const& seqstart, IteratorT const& seqend)
{
if (enabled_macro_counting() || !noexpandmacros.empty()) {
std::string name (macrodef.get_value().c_str());
@@ -257,14 +262,14 @@ public:
count_invocation(name.c_str());
}
- if (!enabled_macro_tracing())
+ if (!enabled_macro_tracing())
return false;
#endif
if (0 == get_level()) {
// output header line
BOOST_WAVE_OSSTREAM stream;
- stream
+ stream
<< macrocall.get_position() << ": "
<< macrocall.get_value() << "(";
@@ -274,7 +279,7 @@ public:
if (i < arguments.size()-1)
stream << ", ";
}
- stream << ")" << std::endl;
+ stream << ")" << std::endl;
output(BOOST_WAVE_GETSTRING(stream));
increment_level();
}
@@ -283,27 +288,27 @@ public:
{
BOOST_WAVE_OSSTREAM stream;
- stream
+ stream
<< macrodef.get_position() << ": see macro definition: "
<< macrodef.get_value() << "(";
// formal argument list
- for (typename std::vector<TokenT>::size_type i = 0;
- i < formal_args.size(); ++i)
+ for (typename std::vector<TokenT>::size_type i = 0;
+ i < formal_args.size(); ++i)
{
stream << formal_args[i].get_value();
if (i < formal_args.size()-1)
stream << ", ";
}
- stream << ")" << std::endl;
+ stream << ")" << std::endl;
output(BOOST_WAVE_GETSTRING(stream));
}
if (formal_args.size() > 0) {
// map formal and real arguments
open_trace_body("invoked with\n");
- for (typename std::vector<TokenT>::size_type j = 0;
- j < formal_args.size(); ++j)
+ for (typename std::vector<TokenT>::size_type j = 0;
+ j < formal_args.size(); ++j)
{
using namespace boost::wave;
@@ -312,15 +317,15 @@ public:
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
if (T_ELLIPSIS == token_id(formal_args[j])) {
// ellipsis
- for (typename ContainerT::size_type k = j;
- k < arguments.size(); ++k)
+ for (typename ContainerT::size_type k = j;
+ k < arguments.size(); ++k)
{
stream << boost::wave::util::impl::as_string(arguments[k]);
if (k < arguments.size()-1)
stream << ", ";
}
- }
- else
+ }
+ else
#endif
{
stream << boost::wave::util::impl::as_string(arguments[j]);
@@ -338,17 +343,17 @@ public:
}
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'expanding_object_like_macro' is called whenever a
+ //
+ // The function 'expanding_object_like_macro' is called whenever a
// object-like macro is to be expanded .
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'macrodef' marks the position, where the macro to expand
+ // The parameter 'macrodef' marks the position, where the macro to expand
// is defined.
//
- // The definition 'definition' holds the macro definition for the macro to
+ // The definition 'definition' holds the macro definition for the macro to
// trace.
//
// The parameter 'macrocall' marks the position, where this macro invoked.
@@ -357,20 +362,20 @@ public:
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
// old signature
template <typename ContainerT>
- void expanding_object_like_macro(TokenT const &macrodef,
+ void expanding_object_like_macro(TokenT const &macrodef,
ContainerT const &definition, TokenT const &macrocall)
{
if (enabled_macro_counting())
count_invocation(macrodef.get_value().c_str());
- if (!enabled_macro_tracing())
+ if (!enabled_macro_tracing())
return;
#else
// new signature
template <typename ContextT, typename ContainerT>
- bool
+ bool
expanding_object_like_macro(ContextT const& ctx,
- TokenT const &macrodef, ContainerT const &definition,
+ TokenT const &macrodef, ContainerT const &definition,
TokenT const &macrocall)
{
if (enabled_macro_counting() || !noexpandmacros.empty()) {
@@ -383,14 +388,14 @@ public:
count_invocation(name.c_str());
}
- if (!enabled_macro_tracing())
+ if (!enabled_macro_tracing())
return false;
#endif
if (0 == get_level()) {
// output header line
BOOST_WAVE_OSSTREAM stream;
- stream
+ stream
<< macrocall.get_position() << ": "
<< macrocall.get_value() << std::endl;
output(BOOST_WAVE_GETSTRING(stream));
@@ -401,7 +406,7 @@ public:
{
BOOST_WAVE_OSSTREAM stream;
- stream
+ stream
<< macrodef.get_position() << ": see macro definition: "
<< macrodef.get_value() << std::endl;
output(BOOST_WAVE_GETSTRING(stream));
@@ -414,14 +419,14 @@ public:
}
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'expanded_macro' is called whenever the expansion of a
+ //
+ // The function 'expanded_macro' is called whenever the expansion of a
// macro is finished but before the rescanning process starts.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'result' contains the token sequence generated as the
+ // The parameter 'result' contains the token sequence generated as the
// result of the macro expansion.
//
///////////////////////////////////////////////////////////////////////////
@@ -445,14 +450,14 @@ public:
}
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'rescanned_macro' is called whenever the rescanning of a
+ //
+ // The function 'rescanned_macro' is called whenever the rescanning of a
// macro is finished.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'result' contains the token sequence generated as the
+ // The parameter 'result' contains the token sequence generated as the
// result of the rescanning.
//
///////////////////////////////////////////////////////////////////////////
@@ -466,7 +471,7 @@ public:
void rescanned_macro(ContextT const& ctx,ContainerT const &result)
#endif
{
- if (!enabled_macro_tracing() || get_level() == 0)
+ if (!enabled_macro_tracing() || get_level() == 0)
return;
BOOST_WAVE_OSSTREAM stream;
@@ -480,37 +485,37 @@ public:
}
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'interpret_pragma' is called whenever a #pragma command
+ //
+ // The function 'interpret_pragma' is called whenever a #pragma command
// directive is found which isn't known to the core Wave library, where
// command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
// which defaults to "wave".
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'pending' may be used to push tokens back into the input
- // stream, which are to be used as the replacement text for the whole
+ // The parameter 'pending' may be used to push tokens back into the input
+ // stream, which are to be used as the replacement text for the whole
// #pragma directive.
//
// The parameter 'option' contains the name of the interpreted pragma.
//
- // The parameter 'values' holds the values of the parameter provided to
+ // The parameter 'values' holds the values of the parameter provided to
// the pragma operator.
//
- // The parameter 'act_token' contains the actual #pragma token, which may
+ // The parameter 'act_token' contains the actual #pragma token, which may
// be used for error output.
//
- // If the return value is 'false', the whole #pragma directive is
+ // If the return value is 'false', the whole #pragma directive is
// interpreted as unknown and a corresponding error message is issued. A
- // return value of 'true' signs a successful interpretation of the given
+ // return value of 'true' signs a successful interpretation of the given
// #pragma.
//
///////////////////////////////////////////////////////////////////////////
template <typename ContextT, typename ContainerT>
- bool
- interpret_pragma(ContextT &ctx, ContainerT &pending,
- typename ContextT::token_type const &option, ContainerT const &valuetokens,
+ bool
+ interpret_pragma(ContextT &ctx, ContainerT &pending,
+ typename ContextT::token_type const &option, ContainerT const &valuetokens,
typename ContextT::token_type const &act_token)
{
typedef typename ContextT::token_type token_type;
@@ -540,7 +545,7 @@ public:
// a corresponding error (actually its a remark),
typename ContextT::string_type msg(
boost::wave::util::impl::as_string(values));
- BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
+ BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
pragma_system_not_enabled,
msg.c_str(), act_token.get_position());
return false;
@@ -554,12 +559,12 @@ public:
// stop the execution and output the argument
typename ContextT::string_type msg(
boost::wave::util::impl::as_string(values));
- BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
+ BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
error_directive, msg.c_str(), act_token.get_position());
return false;
}
if (option.get_value() == "option") {
- // handle different options
+ // handle different options
return interpret_pragma_option(ctx, values, act_token);
}
return false;
@@ -570,26 +575,26 @@ public:
// The function 'emit_line_directive' is called whenever a #line directive
// has to be emitted into the generated output.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'pending' may be used to push tokens back into the input
+ // The parameter 'pending' may be used to push tokens back into the input
// stream, which are to be used instead of the default output generated
// for the #line directive.
//
- // The parameter 'act_token' contains the actual #pragma token, which may
+ // The parameter 'act_token' contains the actual #pragma token, which may
// be used for error output. The line number stored in this token can be
// used as the line number emitted as part of the #line directive.
//
// If the return value is 'false', a default #line directive is emitted
- // by the library. A return value of 'true' will inhibit any further
- // actions, the tokens contained in 'pending' will be copied verbatim
+ // by the library. A return value of 'true' will inhibit any further
+ // actions, the tokens contained in 'pending' will be copied verbatim
// to the output.
//
///////////////////////////////////////////////////////////////////////////
template <typename ContextT, typename ContainerT>
- bool
- emit_line_directive(ContextT const& ctx, ContainerT &pending,
+ bool
+ emit_line_directive(ContextT const& ctx, ContainerT &pending,
typename ContextT::token_type const& act_token)
{
if (!need_emit_line_directives(ctx.get_language()) ||
@@ -611,7 +616,7 @@ public:
pos.set_column(column); // account for '#line'
pending.push_back(result_type(T_SPACE, " ", pos));
- // 21 is the max required size for a 64 bit integer represented as a
+ // 21 is the max required size for a 64 bit integer represented as a
// string
char buffer[22];
@@ -639,36 +644,36 @@ public:
}
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'opened_include_file' is called whenever a file referred
+ //
+ // The function 'opened_include_file' is called whenever a file referred
// by an #include directive was successfully located and opened.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'filename' contains the file system path of the
- // opened file (this is relative to the directory of the currently
+ // The parameter 'filename' contains the file system path of the
+ // opened file (this is relative to the directory of the currently
// processed file or a absolute path depending on the paths given as the
// include search paths).
//
// The include_depth parameter contains the current include file depth.
//
- // The is_system_include parameter denotes, whether the given file was
+ // The is_system_include parameter denotes, whether the given file was
// found as a result of a #include <...> directive.
- //
+ //
///////////////////////////////////////////////////////////////////////////
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
// old signature
- void
- opened_include_file(std::string const &relname, std::string const &absname,
- std::size_t include_depth, bool is_system_include)
+ void
+ opened_include_file(std::string const &relname, std::string const &absname,
+ std::size_t include_depth, bool is_system_include)
{
#else
// new signature
template <typename ContextT>
- void
- opened_include_file(ContextT const& ctx, std::string const &relname,
- std::string const &absname, bool is_system_include)
+ void
+ opened_include_file(ContextT const& ctx, std::string const &relname,
+ std::string const &absname, bool is_system_include)
{
std::size_t include_depth = ctx.get_iteration_depth();
#endif
@@ -688,38 +693,38 @@ public:
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
///////////////////////////////////////////////////////////////////////////
- //
- // The function 'detected_include_guard' is called whenever either a
+ //
+ // The function 'detected_include_guard' is called whenever either a
// include file is about to be added to the list of #pragma once headers.
- // That means this header file will not be opened and parsed again even
+ // That means this header file will not be opened and parsed again even
// if it is specified in a later #include directive.
- // This function is called as the result of a detected include guard
- // scheme.
+ // This function is called as the result of a detected include guard
+ // scheme.
//
- // The implemented heuristics for include guards detects two forms of
+ // The implemented heuristics for include guards detects two forms of
// include guards:
- //
+ //
// #ifndef INCLUDE_GUARD_MACRO
// #define INCLUDE_GUARD_MACRO
// ...
// #endif
- //
+ //
// or
- //
+ //
// if !defined(INCLUDE_GUARD_MACRO)
// #define INCLUDE_GUARD_MACRO
// ...
// #endif
- //
+ //
// note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
- // will work as well). The code allows for any whitespace, newline and single
+ // will work as well). The code allows for any whitespace, newline and single
// '#' tokens before the #if/#ifndef and after the final #endif.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'filename' contains the file system path of the
- // opened file (this is relative to the directory of the currently
+ // The parameter 'filename' contains the file system path of the
+ // opened file (this is relative to the directory of the currently
// processed file or a absolute path depending on the paths given as the
// include search paths).
//
@@ -729,46 +734,46 @@ public:
template <typename ContextT>
void
detected_include_guard(ContextT const& ctx, std::string const& filename,
- std::string const& include_guard)
+ std::string const& include_guard)
{
if (enabled_guard_tracing()) {
guardstrm << include_guard << ":" << std::endl
<< " " << filename << std::endl;
}
}
-#endif
+#endif
///////////////////////////////////////////////////////////////////////////
//
- // The function 'may_skip_whitespace' will be called by the
- // library whenever a token is about to be returned to the calling
- // application.
+ // The function 'may_skip_whitespace' will be called by the
+ // library whenever a token is about to be returned to the calling
+ // application.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The 'token' parameter holds a reference to the current token. The policy
+ // The 'token' parameter holds a reference to the current token. The policy
// is free to change this token if needed.
//
- // The 'skipped_newline' parameter holds a reference to a boolean value
- // which should be set to true by the policy function whenever a newline
- // is going to be skipped.
+ // The 'skipped_newline' parameter holds a reference to a boolean value
+ // which should be set to true by the policy function whenever a newline
+ // is going to be skipped.
//
- // If the return value is true, the given token is skipped and the
- // preprocessing continues to the next token. If the return value is
- // false, the given token is returned to the calling application.
+ // If the return value is true, the given token is skipped and the
+ // preprocessing continues to the next token. If the return value is
+ // false, the given token is returned to the calling application.
//
// ATTENTION!
- // Caution has to be used, because by returning true the policy function
- // is able to force skipping even significant tokens, not only whitespace.
+ // Caution has to be used, because by returning true the policy function
+ // is able to force skipping even significant tokens, not only whitespace.
//
///////////////////////////////////////////////////////////////////////////
template <typename ContextT>
- bool may_skip_whitespace(ContextT const &ctx, TokenT &token,
+ bool may_skip_whitespace(ContextT const &ctx, TokenT &token,
bool &skipped_newline)
{
return this->base_type::may_skip_whitespace(
- ctx, token, need_preserve_comments(ctx.get_language()),
+ ctx, token, need_preserve_comments(ctx.get_language()),
preserve_bol_whitespace, skipped_newline) ?
!preserve_whitespace : false;
}
@@ -778,14 +783,14 @@ public:
// The function 'throw_exception' will be called by the library whenever a
// preprocessing exception occurs.
//
- // The parameter 'ctx' is a reference to the context object used for
+ // The parameter 'ctx' is a reference to the context object used for
// instantiating the preprocessing iterators by the user.
//
- // The parameter 'e' is the exception object containing detailed error
+ // The parameter 'e' is the exception object containing detailed error
// information.
//
// The default behavior is to call the function boost::throw_exception.
- //
+ //
///////////////////////////////////////////////////////////////////////////
template <typename ContextT>
void
@@ -798,7 +803,7 @@ public:
boost::throw_exception(e);
#endif
}
- using base_type::throw_exception;
+ using base_type::throw_exception;
protected:
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
@@ -820,8 +825,8 @@ protected:
///////////////////////////////////////////////////////////////////////////
// Interpret the different Wave specific pragma directives/operators
template <typename ContextT, typename ContainerT>
- bool
- interpret_pragma_trace(ContextT& ctx, ContainerT const &values,
+ bool
+ interpret_pragma_trace(ContextT& ctx, ContainerT const &values,
typename ContextT::token_type const &act_token)
{
typedef typename ContextT::token_type token_type;
@@ -833,8 +838,8 @@ protected:
token_type const &value = values.front();
if (value.get_value() == "enable" ||
- value.get_value() == "on" ||
- value.get_value() == "1")
+ value.get_value() == "on" ||
+ value.get_value() == "1")
{
// #pragma wave trace(enable)
enable_tracing(static_cast<trace_flags>(
@@ -842,8 +847,8 @@ protected:
valid_option = true;
}
else if (value.get_value() == "disable" ||
- value.get_value() == "off" ||
- value.get_value() == "0")
+ value.get_value() == "off" ||
+ value.get_value() == "0")
{
// #pragma wave trace(disable)
enable_tracing(static_cast<trace_flags>(
@@ -860,8 +865,8 @@ protected:
option_str += boost::wave::util::impl::as_string(values);
option_str += ")";
}
- BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
- ill_formed_pragma_option, option_str.c_str(),
+ BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
+ ill_formed_pragma_option, option_str.c_str(),
act_token.get_position());
return false;
}
@@ -871,8 +876,8 @@ protected:
///////////////////////////////////////////////////////////////////////////
// interpret the pragma wave option(preserve: [0|1|2|3|push|pop]) directive
template <typename ContextT>
- static bool
- interpret_pragma_option_preserve_set(int mode, bool &preserve_whitespace,
+ static bool
+ interpret_pragma_option_preserve_set(int mode, bool &preserve_whitespace,
bool& preserve_bol_whitespace, ContextT &ctx)
{
switch(mode) {
@@ -919,7 +924,7 @@ protected:
}
template <typename ContextT, typename IteratorT>
- bool
+ bool
interpret_pragma_option_preserve(ContextT &ctx, IteratorT &it,
IteratorT end, typename ContextT::token_type const &act_token)
{
@@ -950,14 +955,14 @@ protected:
else if ((*it).get_value() == "pop") {
// test for mismatched push/pop #pragmas
if (preserve_options.empty()) {
- BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
- pragma_mismatched_push_pop, "preserve",
+ BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
+ pragma_mismatched_push_pop, "preserve",
act_token.get_position());
}
// pop output preserve from the internal option stack
bool result = interpret_pragma_option_preserve_set(
- preserve_options.top(), preserve_whitespace,
+ preserve_options.top(), preserve_whitespace,
preserve_bol_whitespace, ctx);
preserve_options.pop();
return result;
@@ -965,18 +970,18 @@ protected:
return false;
}
- if (T_PP_NUMBER != id)
+ if (T_PP_NUMBER != id)
return false;
using namespace std; // some platforms have atoi in namespace std
return interpret_pragma_option_preserve_set(
- atoi((*it).get_value().c_str()), preserve_whitespace,
+ atoi((*it).get_value().c_str()), preserve_whitespace,
preserve_bol_whitespace, ctx);
}
// interpret the pragma wave option(line: [0|1|2|push|pop]) directive
template <typename ContextT, typename IteratorT>
- bool
+ bool
interpret_pragma_option_line(ContextT &ctx, IteratorT &it,
IteratorT end, typename ContextT::token_type const &act_token)
{
@@ -985,7 +990,7 @@ protected:
token_id id = util::impl::skip_whitespace(it, end);
if (T_COLON == id)
id = util::impl::skip_whitespace(it, end);
-
+
// implement push/pop
if (T_IDENTIFIER == id) {
if ((*it).get_value() == "push") {
@@ -1002,8 +1007,8 @@ protected:
else if ((*it).get_value() == "pop") {
// test for mismatched push/pop #pragmas
if (line_options.empty()) {
- BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
- pragma_mismatched_push_pop, "line",
+ BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
+ pragma_mismatched_push_pop, "line",
act_token.get_position());
}
@@ -1018,7 +1023,7 @@ protected:
return false;
}
- if (T_PP_NUMBER != id)
+ if (T_PP_NUMBER != id)
return false;
using namespace std; // some platforms have atoi in namespace std
@@ -1033,17 +1038,18 @@ protected:
return false;
}
- // interpret the pragma wave option(output: ["filename"|null|default|push|pop])
+ // interpret the pragma wave option(output: ["filename"|null|default|push|pop])
// directive
template <typename ContextT>
- bool
- interpret_pragma_option_output_open(boost::filesystem::path &fpath,
+ bool
+ interpret_pragma_option_output_open(boost::filesystem::path &fpath,
ContextT& ctx, typename ContextT::token_type const &act_token)
{
namespace fs = boost::filesystem;
// ensure all directories for this file do exist
- fs::create_directories(boost::wave::util::branch_path(fpath));
+ boost::wave::util::create_directories(
+ boost::wave::util::branch_path(fpath));
// figure out, whether the file has been written to by us, if yes, we
// append any output to this file, otherwise we overwrite it
@@ -1059,17 +1065,22 @@ protected:
// open the new file
outputstrm.open(fpath.string().c_str(), mode);
- if (!outputstrm.is_open()) {
- BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
+ if (!outputstrm.is_open()) {
+ BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
could_not_open_output_file,
fpath.string().c_str(), act_token.get_position());
return false;
}
+
+ // write license text, if file was created and if requested
+ if (mode == std::ios::out && !license_info.empty())
+ outputstrm << license_info;
+
generate_output = true;
current_outfile = fpath;
- return true;
+ return true;
}
-
+
bool interpret_pragma_option_output_close(bool generate)
{
if (outputstrm.is_open())
@@ -1080,7 +1091,7 @@ protected:
}
template <typename ContextT, typename IteratorT>
- bool
+ bool
interpret_pragma_option_output(ContextT &ctx, IteratorT &it,
IteratorT end, typename ContextT::token_type const &act_token)
{
@@ -1097,7 +1108,7 @@ protected:
bool result = false;
if (T_STRINGLIT == id) {
namespace fs = boost::filesystem;
-
+
string_type fname ((*it).get_value());
fs::path fpath (boost::wave::util::create_path(
util::impl::unescape_lit(fname.substr(1, fname.size()-2)).c_str()));
@@ -1108,7 +1119,7 @@ protected:
if ((*it).get_value() == "null") {
// suppress all output from this point on
result = interpret_pragma_option_output_close(false);
- }
+ }
else if ((*it).get_value() == "push") {
// initialize the current_outfile, if appropriate
if (output_options.empty() && current_outfile.empty() &&
@@ -1126,8 +1137,8 @@ protected:
else if ((*it).get_value() == "pop") {
// test for mismatched push/pop #pragmas
if (output_options.empty()) {
- BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
- pragma_mismatched_push_pop, "output",
+ BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
+ pragma_mismatched_push_pop, "output",
act_token.get_position());
return false;
}
@@ -1138,7 +1149,7 @@ protected:
current_outfile = opts.second;
if (!current_outfile.empty()) {
// re-open the last file
- result = interpret_pragma_option_output_open(current_outfile,
+ result = interpret_pragma_option_output_open(current_outfile,
ctx, act_token);
}
else {
@@ -1158,7 +1169,7 @@ protected:
else {
// there was a file name on the command line
fs::path fpath(boost::wave::util::create_path(default_outfile));
- result = interpret_pragma_option_output_open(fpath, ctx,
+ result = interpret_pragma_option_output_open(fpath, ctx,
act_token);
}
}
@@ -1234,8 +1245,8 @@ protected:
///////////////////////////////////////////////////////////////////////////
// interpret the pragma wave option() directives
template <typename ContextT, typename ContainerT>
- bool
- interpret_pragma_option(ContextT &ctx, ContainerT const &cvalues,
+ bool
+ interpret_pragma_option(ContextT &ctx, ContainerT const &cvalues,
typename ContextT::token_type const &act_token)
{
using namespace boost::wave;
@@ -1254,17 +1265,17 @@ protected:
token_type const &value = *it;
if (value.get_value() == "preserve") {
// #pragma wave option(preserve: [0|1|2|3|push|pop])
- valid_option = interpret_pragma_option_preserve(ctx, it, end,
+ valid_option = interpret_pragma_option_preserve(ctx, it, end,
act_token);
}
else if (value.get_value() == "line") {
// #pragma wave option(line: [0|1|2|push|pop])
- valid_option = interpret_pragma_option_line(ctx, it, end,
+ valid_option = interpret_pragma_option_line(ctx, it, end,
act_token);
}
else if (value.get_value() == "output") {
// #pragma wave option(output: ["filename"|null|default|push|pop])
- valid_option = interpret_pragma_option_output(ctx, it, end,
+ valid_option = interpret_pragma_option_output(ctx, it, end,
act_token);
}
@@ -1277,12 +1288,12 @@ protected:
option_str += util::impl::as_string(values);
option_str += ")";
}
- BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
+ BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
ill_formed_pragma_option,
option_str.c_str(), act_token.get_position());
return false;
}
-
+
token_id id = util::impl::skip_whitespace(it, end);
if (id == T_COMMA)
util::impl::skip_whitespace(it, end);
@@ -1294,8 +1305,8 @@ protected:
// interpret the #pragma wave system() directive
template <typename ContextT, typename ContainerT>
bool
- interpret_pragma_system(ContextT& ctx, ContainerT &pending,
- ContainerT const &values,
+ interpret_pragma_system(ContextT& ctx, ContainerT &pending,
+ ContainerT const &values,
typename ContextT::token_type const &act_token)
{
typedef typename ContextT::token_type token_type;
@@ -1314,25 +1325,25 @@ protected:
string_type error_str("unable to spawn command: ");
error_str += native_cmd;
- BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
+ BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
ill_formed_pragma_option,
error_str.c_str(), act_token.get_position());
return false;
}
- // rescan the content of the stdout_file and insert it as the
+ // rescan the content of the stdout_file and insert it as the
// _Pragma replacement
typedef typename ContextT::lexer_type lexer_type;
typedef typename ContextT::input_policy_type input_policy_type;
typedef boost::wave::iteration_context<
- ContextT, lexer_type, input_policy_type>
+ ContextT, lexer_type, input_policy_type>
iteration_context_type;
- iteration_context_type iter_ctx(ctx, stdout_file.c_str(),
+ iteration_context_type iter_ctx(ctx, stdout_file.c_str(),
act_token.get_position(), ctx.get_language());
ContainerT pragma;
- for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first)
+ for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first)
pragma.push_back(*iter_ctx.first);
// prepend the newly generated token sequence to the 'pending' container
@@ -1345,14 +1356,14 @@ protected:
}
///////////////////////////////////////////////////////////////////////////
- // The function enable_tracing is called, whenever the status of the
+ // The function enable_tracing is called, whenever the status of the
// tracing was changed.
// The parameter 'enable' is to be used as the new tracing status.
- void enable_tracing(trace_flags flags)
+ void enable_tracing(trace_flags flags)
{ logging_flags = flags; }
// The function tracing_enabled should return the current tracing status.
- trace_flags tracing_enabled()
+ trace_flags tracing_enabled()
{ return logging_flags; }
// Helper functions for generating the trace output
@@ -1389,21 +1400,21 @@ protected:
int decrement_level() { BOOST_ASSERT(level > 0); return --level; }
int get_level() const { return level; }
- bool enabled_macro_tracing() const
- {
- return (flags & trace_macros) && (logging_flags & trace_macros);
+ bool enabled_macro_tracing() const
+ {
+ return (flags & trace_macros) && (logging_flags & trace_macros);
}
- bool enabled_include_tracing() const
- {
- return (flags & trace_includes);
+ bool enabled_include_tracing() const
+ {
+ return (flags & trace_includes);
}
- bool enabled_guard_tracing() const
- {
- return (flags & trace_guards);
+ bool enabled_guard_tracing() const
+ {
+ return (flags & trace_guards);
}
- bool enabled_macro_counting() const
- {
- return logging_flags & trace_macro_counts;
+ bool enabled_macro_counting() const
+ {
+ return logging_flags & trace_macro_counts;
}
void count_invocation(std::string const& name)
@@ -1431,8 +1442,8 @@ protected:
}
else if (value.get_value() == "1") {
// print out the current elapsed time
- std::cerr
- << value.get_position() << ": "
+ std::cerr
+ << value.get_position() << ": "
<< elapsed_time.format_elapsed_time()
<< std::endl;
}
@@ -1459,7 +1470,7 @@ private:
bool preserve_bol_whitespace; // enable begin of line whitespace preservation
bool& generate_output; // allow generated tokens to be streamed to output
std::string const& default_outfile; // name of the output file given on command line
- boost::filesystem::path current_outfile; // name of the current output file
+ boost::filesystem::path current_outfile; // name of the current output file
stop_watch elapsed_time; // trace timings
std::set<boost::filesystem::path> written_by_us; // all files we have written to
@@ -1473,6 +1484,8 @@ private:
bool emit_relative_filenames; // emit relative names in #line directives
std::set<std::string> noexpandmacros; // list of macros not to expand
+
+ std::string license_info; // text to pre-pend to all generated output files
};
#undef BOOST_WAVE_GETSTRING