]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/util/doc.jam
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / util / doc.jam
1 # Copyright 2002, 2005 Dave Abrahams
2 # Copyright 2002, 2003, 2006 Rene Rivera
3 # Copyright 2003 Vladimir Prus
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
6
7 # Documentation system, handles --help requests.
8 # It defines rules that attach documentation to modules, rules, and variables.
9 # Collects and generates documentation for the various parts of the build
10 # system. The documentation is collected from comments integrated into the code.
11
12 import modules ;
13 import print ;
14 import set ;
15 import container ;
16 import "class" ;
17 import sequence ;
18 import path ;
19
20
21 # The type of output to generate.
22 # "console" is formated text echoed to the console (the default);
23 # "text" is formated text appended to the output file;
24 # "html" is HTML output to the file.
25 #
26 help-output = console ;
27
28
29 # The file to output documentation to when generating "text" or "html" help.
30 # This is without extension as the extension is determined by the type of
31 # output.
32 #
33 help-output-file = help ;
34
35 # Whether to include local rules in help output.
36 #
37 .option.show-locals ?= ;
38
39 # When showing documentation for a module, whether to also generate
40 # automatically the detailed docs for each item in the module.
41 #
42 .option.detailed ?= ;
43
44 # Generate debug output as the help is generated and modules are parsed.
45 #
46 .option.debug ?= ;
47
48 # These are all the options available for enabling or disabling to control the
49 # help system in various ways. Options can be enabled or disabled with
50 # '--help-enable-<option>', and '--help-disable-<option>' respectively.
51 #
52 .option-description = Help Options ;
53
54 # Enable or disable a documentation option.
55 #
56 local rule set-option (
57 option # The option name.
58 : value ? # Enabled (non-empty), or disabled (empty)
59 )
60 {
61 .option.$(option) = $(value) ;
62 }
63
64
65 # Set the type of output.
66 #
67 local rule set-output ( type )
68 {
69 help-output = $(type) ;
70 }
71
72
73 # Set the output to a file.
74 #
75 local rule set-output-file ( file )
76 {
77 help-output-file = $(file) ;
78 }
79
80
81 # Extracts the brief comment from a complete comment. The brief comment is the
82 # first sentence.
83 #
84 local rule brief-comment (
85 docs * # The comment documentation.
86 )
87 {
88 local d = $(docs:J=" ") ;
89 local p = [ MATCH ".*([.])$" : $(d) ] ;
90 if ! $(p) { d = $(d)"." ; }
91 d = $(d)" " ;
92 local m = [ MATCH "^([^.]+[.])(.*)" : $(d) ] ;
93 local brief = $(m[1]) ;
94 while $(m[2]) && [ MATCH "^([^ ])" : $(m[2]) ]
95 {
96 m = [ MATCH "^([^.]+[.])(.*)" : $(m[2]) ] ;
97 brief += $(m[1]) ;
98 }
99 return $(brief:J="") ;
100 }
101
102
103 # Specifies the documentation for the current module.
104 #
105 local rule set-module-doc (
106 module-name ? # The name of the module to document.
107 : docs * # The documentation for the module.
108 )
109 {
110 module-name ?= * ;
111
112 $(module-name).brief = [ brief-comment $(docs) ] ;
113 $(module-name).docs = $(docs) ;
114
115 if ! $(module-name) in $(documented-modules)
116 {
117 documented-modules += $(module-name) ;
118 }
119 }
120
121
122 # Specifies the documentation for the current module.
123 #
124 local rule set-module-copyright (
125 module-name ? # The name of the module to document.
126 : copyright * # The copyright for the module.
127 )
128 {
129 module-name ?= * ;
130
131 $(module-name).copy-brief = [ brief-comment $(copyright) ] ;
132 $(module-name).copy-docs = $(docs) ;
133
134 if ! $(module-name) in $(documented-modules)
135 {
136 documented-modules += $(module-name) ;
137 }
138 }
139
140
141 # Specifies the documentation for a rule in the current module. If called in the
142 # global module, this documents a global rule.
143 #
144 local rule set-rule-doc (
145 name # The name of the rule.
146 module-name ? # The name of the module to document.
147 is-local ? # Whether the rule is local to the module.
148 : docs * # The documentation for the rule.
149 )
150 {
151 module-name ?= * ;
152
153 $(module-name).$(name).brief = [ brief-comment $(docs) ] ;
154 $(module-name).$(name).docs = $(docs) ;
155 $(module-name).$(name).is-local = $(is-local) ;
156
157 if ! $(name) in $($(module-name).rules)
158 {
159 $(module-name).rules += $(name) ;
160 }
161 }
162
163
164 # Specify a class, will turn a rule into a class.
165 #
166 local rule set-class-doc (
167 name # The name of the class.
168 module-name ? # The name of the module to document.
169 : super-name ? # The super class name.
170 )
171 {
172 module-name ?= * ;
173
174 $(module-name).$(name).is-class = true ;
175 $(module-name).$(name).super-name = $(super-name) ;
176 $(module-name).$(name).class-rules =
177 [ MATCH "^($(name)[.].*)" : $($(module-name).rules) ] ;
178 $(module-name).$($(module-name).$(name).class-rules).is-class-rule = true ;
179
180 $(module-name).classes += $(name) ;
181 $(module-name).class-rules += $($(module-name).$(name).class-rules) ;
182 $(module-name).rules =
183 [ set.difference $($(module-name).rules) :
184 $(name) $($(module-name).$(name).class-rules) ] ;
185 }
186
187
188 # Set the argument call signature of a rule.
189 #
190 local rule set-rule-arguments-signature (
191 name # The name of the rule.
192 module-name ? # The name of the module to document.
193 : signature * # The arguments signature.
194 )
195 {
196 module-name ?= * ;
197
198 $(module-name).$(name).signature = $(signature) ;
199 }
200
201
202 # Specifies the documentation for an argument of a rule.
203 #
204 local rule set-argument-doc (
205 name # The name of the argument.
206 qualifier # Argument syntax qualifier, "*", "+", etc.
207 rule-name # The name of the rule.
208 module-name ? # THe optional name of the module.
209 : docs * # The documentation.
210 )
211 {
212 module-name ?= * ;
213
214 $(module-name).$(rule-name).args.$(name).qualifier = $(qualifier) ;
215 $(module-name).$(rule-name).args.$(name).docs = $(docs) ;
216
217 if ! $(name) in $($(module-name).$(rule-name).args)
218 {
219 $(module-name).$(rule-name).args += $(name) ;
220 }
221 }
222
223
224 # Specifies the documentation for a variable in the current module. If called in
225 # the global module, the global variable is documented.
226 #
227 local rule set-variable-doc (
228 name # The name of the variable.
229 default # The default value.
230 initial # The initial value.
231 module-name ? # The name of the module to document.
232 : docs * # The documentation for the variable.
233 )
234 {
235 module-name ?= * ;
236
237 $(module-name).$(name).brief = [ brief-comment $(docs) ] ;
238 $(module-name).$(name).default = $(default) ;
239 $(module-name).$(name).initial = $(initial) ;
240 $(module-name).$(name).docs = $(docs) ;
241
242 if ! $(name) in $($(module-name).variables)
243 {
244 $(module-name).variables += $(name) ;
245 }
246 }
247
248
249 # Generates a general description of the documentation and help system.
250 #
251 local rule print-help-top ( )
252 {
253 print.section "General command line usage" ;
254
255 print.text " b2 [options] [properties] [targets]
256
257 Options, properties and targets can be specified in any order.
258 " ;
259
260 print.section "Important Options" ;
261
262 print.list-start ;
263 print.list-item "--clean Remove targets instead of building" ;
264 print.list-item "-a Rebuild everything" ;
265 print.list-item "-n Don't execute the commands, only print them" ;
266 print.list-item "-d+2 Show commands as they are executed" ;
267 print.list-item "-d0 Suppress all informational messages" ;
268 print.list-item "-q Stop at first error" ;
269 print.list-item "--reconfigure Rerun all configuration checks" ;
270 print.list-item "--debug-configuration Diagnose configuration" ;
271 print.list-item "--debug-building Report which targets are built with what properties" ;
272 print.list-item "--debug-generator Diagnose generator search/execution" ;
273 print.list-end ;
274
275 print.section "Further Help"
276 The following options can be used to obtain additional documentation.
277 ;
278
279 print.list-start ;
280 print.list-item "--help-options Print more obscure command line options." ;
281 print.list-item "--help-internal Boost.Build implementation details." ;
282 print.list-item "--help-doc-options Implementation details doc formatting." ;
283 print.list-end ;
284 }
285
286
287 # Generate Jam/Boost.Jam command usage information.
288 #
289 local rule print-help-usage ( )
290 {
291 print.section "Boost.Build Usage"
292 "b2 [ options... ] targets..."
293 ;
294 print.list-start ;
295 print.list-item -a;
296 Build all targets, even if they are current. ;
297 print.list-item -fx;
298 Read '"x"' as the Jamfile for building instead of searching for the
299 Boost.Build system. ;
300 print.list-item -jx;
301 Run up to '"x"' commands concurrently. ;
302 print.list-item -n;
303 Do not execute build commands. Instead print out the commands as they
304 would be executed if building. ;
305 print.list-item -ox;
306 Output the used build commands to file '"x"'. ;
307 print.list-item -q;
308 Quit as soon as a build failure is encountered. Without this option
309 Boost.Jam will continue building as many targets as it can. ;
310 print.list-item -sx=y;
311 Sets a Jam variable '"x"' to the value '"y"', overriding any value that
312 variable would have from the environment. ;
313 print.list-item -tx;
314 Rebuild the target '"x"', even if it is up-to-date. ;
315 print.list-item -v;
316 Display the version of b2. ;
317 print.list-item --x;
318 Any option not explicitly handled by Boost.Build remains available to
319 build scripts using the '"ARGV"' variable. ;
320 print.list-item --abbreviate-paths;
321 Use abbreviated paths for targets. ;
322 print.list-item --hash;
323 Shorten target paths by using an MD5 hash. ;
324 print.list-item -dconsole;
325 Run the interactive debugger. Cannot be used with any other option. ;
326 print.list-item -dn;
327 Enables output of diagnostic messages. The debug level '"n"' and all
328 below it are enabled by this option. ;
329 print.list-item -d+n;
330 Enables output of diagnostic messages. Only the output for debug level
331 '"n"' is enabled. ;
332 print.list-end ;
333 print.section "Debug Levels"
334 Each debug level shows a different set of information. Usually with
335 higher levels producing more verbose information. The following levels
336 are supported: ;
337 print.list-start ;
338 print.list-item 0;
339 Turn off all diagnostic output. Only errors are reported. ;
340 print.list-item 1;
341 Show the actions taken for building targets, as they are executed. ;
342 print.list-item 2;
343 Show "quiet" actions and display all action text, as they are executed. ;
344 print.list-item 3;
345 Show dependency analysis, and target/source timestamps/paths. ;
346 print.list-item 4;
347 Show arguments of shell invocations. ;
348 print.list-item 5;
349 Show rule invocations and variable expansions. ;
350 print.list-item 6;
351 Show directory/header file/archive scans, and attempts at binding to targets. ;
352 print.list-item 7;
353 Show variable settings. ;
354 print.list-item 8;
355 Show variable fetches, variable expansions, and evaluation of '"if"' expressions. ;
356 print.list-item 9;
357 Show variable manipulation, scanner tokens, and memory usage. ;
358 print.list-item 10;
359 Show execution times for rules. ;
360 print.list-item 11;
361 Show parsing progress of Jamfiles. ;
362 print.list-item 12;
363 Show graph for target dependencies. ;
364 print.list-item 13;
365 Show changes in target status (fate). ;
366 print.list-end ;
367 }
368
369 # Generates description of options controlling the help system. This
370 # automatically reads the options as all variables in the module given
371 # with the name `module-name` of the form ".option.*".
372 #
373 local rule print-help-options (
374 module-name
375 )
376 {
377 local options-to-list = [ MATCH ^[.]option[.](.*) : $($(module-name).variables) ] ;
378 if $(options-to-list)
379 {
380 local option-title = $($(module-name)..option-description.initial) ;
381 if ! $(option-title) || $(option-title) = "(empty)"
382 {
383 option-title = "$(module-name) Options" ;
384 }
385 local option-description = $(option-title)
386 $($(module-name)..option-description.docs) ;
387 print.section $(option-description) ;
388 print.list-start ;
389 for local option in [ sequence.insertion-sort $(options-to-list) ]
390 {
391 local def = disabled ;
392 if $($(module-name)..option.$(option).default) != "(empty)"
393 {
394 def = $($(module-name)..option.$(option).default) ;
395 }
396 print.list-item $(option): $($(module-name)..option.$(option).docs)
397 Default is $(def). ;
398 }
399 print.list-end ;
400 }
401 }
402
403
404 # Generate brief documentation for all the known items in the section for a
405 # module. Possible sections are: "rules", and "variables".
406 #
407 local rule print-help-module-section (
408 module # The module name.
409 section # rules or variables.
410 : section-head # The title of the section.
411 section-description * # The detailed description of the section.
412 )
413 {
414 if $($(module).$(section))
415 {
416 print.section $(section-head) $(section-description) ;
417 print.list-start ;
418 for local item in [ sequence.insertion-sort $($(module).$(section)) ]
419 {
420 local show = ;
421 if ! $($(module).$(item).is-local)
422 {
423 show = yes ;
424 }
425 if $(.option.show-locals)
426 {
427 show = yes ;
428 }
429 if $(show)
430 {
431 print.list-item $(item): $($(module).$(item).brief) ;
432 }
433 }
434 print.list-end ;
435 }
436 }
437
438
439 # Generate documentation for all possible modules. We attempt to list all known
440 # modules together with a brief description of each.
441 #
442 local rule print-help-all (
443 ignored # Usually the module name, but is ignored here.
444 )
445 {
446 print.section "Modules"
447 "These are all the known modules. Use --help <module> to get more"
448 "detailed information."
449 ;
450 if $(documented-modules)
451 {
452 print.list-start ;
453 for local module-name in [ sequence.insertion-sort $(documented-modules) ]
454 {
455 # The brief docs for each module.
456 print.list-item $(module-name): $($(module-name).brief) ;
457 }
458 print.list-end ;
459 }
460 # The documentation for each module when details are requested.
461 if $(documented-modules) && $(.option.detailed)
462 {
463 for local module-name in [ sequence.insertion-sort $(documented-modules) ]
464 {
465 # The brief docs for each module.
466 print-help-module $(module-name) ;
467 }
468 }
469 }
470
471
472 # Generate documentation for a module. Basic information about the module is
473 # generated.
474 #
475 local rule print-help-module (
476 module-name # The module to generate docs for.
477 )
478 {
479 # Print the docs.
480 print.section "Module '$(module-name)'" $($(module-name).docs) ;
481
482 # Print out the documented classes.
483 print-help-module-section $(module-name) classes : "Module '$(module-name)' classes"
484 Use --help $(module-name).<class-name> to get more information. ;
485
486 # Print out the documented rules.
487 print-help-module-section $(module-name) rules : "Module '$(module-name)' rules"
488 Use --help $(module-name).<rule-name> to get more information. ;
489
490 # Print out the documented variables.
491 print-help-module-section $(module-name) variables : "Module '$(module-name)' variables"
492 Use --help $(module-name).<variable-name> to get more information. ;
493
494 # Print out all the same information but indetailed form.
495 if $(.option.detailed)
496 {
497 print-help-classes $(module-name) ;
498 print-help-rules $(module-name) ;
499 print-help-variables $(module-name) ;
500 }
501 }
502
503
504 # Generate documentation for a set of rules in a module.
505 #
506 local rule print-help-rules (
507 module-name # Module of the rules.
508 : name * # Optional list of rules to describe.
509 )
510 {
511 name ?= $($(module-name).rules) ;
512 if [ set.intersection $(name) : $($(module-name).rules) $($(module-name).class-rules) ]
513 {
514 # Print out the given rules.
515 for local rule-name in [ sequence.insertion-sort $(name) ]
516 {
517 if $(.option.show-locals) || ! $($(module-name).$(rule-name).is-local)
518 {
519 local signature = $($(module-name).$(rule-name).signature:J=" ") ;
520 signature ?= "" ;
521 print.section "Rule '$(module-name).$(rule-name) ( $(signature) )'"
522 $($(module-name).$(rule-name).docs) ;
523 if $($(module-name).$(rule-name).args)
524 {
525 print.list-start ;
526 for local arg-name in $($(module-name).$(rule-name).args)
527 {
528 print.list-item $(arg-name): $($(module-name).$(rule-name).args.$(arg-name).docs) ;
529 }
530 print.list-end ;
531 }
532 }
533 }
534 }
535 }
536
537
538 # Generate documentation for a set of classes in a module.
539 #
540 local rule print-help-classes (
541 module-name # Module of the classes.
542 : name * # Optional list of classes to describe.
543 )
544 {
545 name ?= $($(module-name).classes) ;
546 if [ set.intersection $(name) : $($(module-name).classes) ]
547 {
548 # Print out the given classes.
549 for local class-name in [ sequence.insertion-sort $(name) ]
550 {
551 if $(.option.show-locals) || ! $($(module-name).$(class-name).is-local)
552 {
553 local signature = $($(module-name).$(class-name).signature:J=" ") ;
554 signature ?= "" ;
555 print.section "Class '$(module-name).$(class-name) ( $(signature) )'"
556 $($(module-name).$(class-name).docs)
557 "Inherits from '"$($(module-name).$(class-name).super-name)"'." ;
558 if $($(module-name).$(class-name).args)
559 {
560 print.list-start ;
561 for local arg-name in $($(module-name).$(class-name).args)
562 {
563 print.list-item $(arg-name): $($(module-name).$(class-name).args.$(arg-name).docs) ;
564 }
565 print.list-end ;
566 }
567 }
568
569 # Print out the documented rules of the class.
570 print-help-module-section $(module-name) $(class-name).class-rules : "Class '$(module-name).$(class-name)' rules"
571 Use --help $(module-name).<rule-name> to get more information. ;
572
573 # Print out all the rules if details are requested.
574 if $(.option.detailed)
575 {
576 print-help-rules $(module-name) : $($(module-name).$(class-name).class-rules) ;
577 }
578 }
579 }
580 }
581
582
583 # Generate documentation for a set of variables in a module.
584 #
585 local rule print-help-variables (
586 module-name ? # Module of the variables.
587 : name * # Optional list of variables to describe.
588 )
589 {
590 name ?= $($(module-name).variables) ;
591 if [ set.intersection $(name) : $($(module-name).variables) ]
592 {
593 # Print out the given variables.
594 for local variable-name in [ sequence.insertion-sort $(name) ]
595 {
596 print.section "Variable '$(module-name).$(variable-name)'" $($(module-name).$(variable-name).docs) ;
597 if $($(module-name).$(variable-name).default) ||
598 $($(module-name).$(variable-name).initial)
599 {
600 print.list-start ;
601 if $($(module-name).$(variable-name).default)
602 {
603 print.list-item "default value:" '$($(module-name).$(variable-name).default:J=" ")' ;
604 }
605 if $($(module-name).$(variable-name).initial)
606 {
607 print.list-item "initial value:" '$($(module-name).$(variable-name).initial:J=" ")' ;
608 }
609 print.list-end ;
610 }
611 }
612 }
613 }
614
615
616 # Generate documentation for a project.
617 #
618 local rule print-help-project (
619 unused ?
620 : jamfile * # The project Jamfile.
621 )
622 {
623 if $(jamfile<$(jamfile)>.docs)
624 {
625 # Print the docs.
626 print.section "Project-specific help"
627 Project has jamfile at $(jamfile) ;
628
629 print.lines $(jamfile<$(jamfile)>.docs) "" ;
630 }
631 }
632
633
634 # Generate documentation for a config file.
635 #
636 local rule print-help-config (
637 unused ?
638 : type # The type of configuration file user or site.
639 config-file # The configuration Jamfile.
640 )
641 {
642 if $(jamfile<$(config-file)>.docs)
643 {
644 # Print the docs.
645 print.section "Configuration help"
646 Configuration file at $(config-file) ;
647
648 print.lines $(jamfile<$(config-file)>.docs) "" ;
649 }
650 }
651
652
653 ws = " " ;
654
655 # Extract the text from a block of comments.
656 #
657 local rule extract-comment (
658 var # The name of the variable to extract from.
659 )
660 {
661 local comment = ;
662 local line = $($(var)[1]) ;
663 local l = [ MATCH "^[$(ws)]*(#)(.*)$" : $(line) ] ;
664 while $(l[1]) && $($(var))
665 {
666 if $(l[2]) { comment += [ MATCH "^[$(ws)]?(.*)$" : $(l[2]) ] ; }
667 else { comment += "" ; }
668 $(var) = $($(var)[2-]) ;
669 line = $($(var)[1]) ;
670 l = [ MATCH "^[$(ws)]*(#)(.*)$" : $(line) ] ;
671 }
672 return $(comment) ;
673 }
674
675
676 # Extract s single line of Jam syntax, ignoring any comments.
677 #
678 local rule extract-syntax (
679 var # The name of the variable to extract from.
680 )
681 {
682 local syntax = ;
683 local line = $($(var)[1]) ;
684 while ! $(syntax) && ! [ MATCH "^[$(ws)]*(#)" : $(line) ] && $($(var))
685 {
686 local m = [ MATCH "^[$(ws)]*(.*)$" : $(line) ] ;
687 if $(m)
688 {
689 syntax = $(m) ;
690 }
691 $(var) = $($(var)[2-]) ;
692 line = $($(var)[1]) ;
693 }
694 return $(syntax) ;
695 }
696
697
698 # Extract the next token, this is either a single Jam construct or a comment as
699 # a single token.
700 #
701 local rule extract-token (
702 var # The name of the variable to extract from.
703 )
704 {
705 local parts = ;
706 while ! $(parts)
707 {
708 parts = [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]*(.*)" : $($(var)[1]) ] ;
709 if ! $(parts)
710 {
711 $(var) = $($(var)[2-]) ;
712 }
713 }
714 local token = ;
715 if [ MATCH "^(#)" : $(parts[1]) ]
716 {
717 token = $(parts:J=" ") ;
718 $(var) = $($(var)[2-]) ;
719 }
720 else
721 {
722 token = $(parts[1]) ;
723 $(var) = $(parts[2-]:J=" ") $($(var)[2-]) ;
724 }
725 return $(token) ;
726 }
727
728
729 # Scan for a rule declaration as the next item in the variable.
730 #
731 local rule scan-rule (
732 syntax ? # The first part of the text which contains the rule declaration.
733 : var # The name of the variable to extract from.
734 )
735 {
736 local rule-parts =
737 [ MATCH "^[$(ws)]*(rule|local[$(ws)]*rule)[$(ws)]+([^$(ws)]+)[$(ws)]*(.*)" : $(syntax:J=" ") ] ;
738 if $(rule-parts[1])
739 {
740 # Mark as doc for rule.
741 local rule-name = $(rule-parts[2]) ;
742 if $(scope-name)
743 {
744 rule-name = $(scope-name).$(rule-name) ;
745 }
746 local is-local = [ MATCH "^(local).*" : $(rule-parts[1]) ] ;
747 if $(comment-block)
748 {
749 set-rule-doc $(rule-name) $(module-name) $(is-local) : $(comment-block) ;
750 }
751 # Parse args of rule.
752 $(var) = $(rule-parts[3-]) $($(var)) ;
753 set-rule-arguments-signature $(rule-name) $(module-name) : [ scan-rule-arguments $(var) ] ;
754 # Scan within this rules scope.
755 local scope-level = [ extract-token $(var) ] ;
756 local scope-name = $(rule-name) ;
757 while $(scope-level) && $($(var))
758 {
759 local comment-block = [ extract-comment $(var) ] ;
760 local syntax-block = [ extract-syntax $(var) ] ;
761 if [ scan-rule $(syntax-block) : $(var) ]
762 {
763 }
764 else if [ MATCH "^(\\{)" : $(syntax-block) ]
765 {
766 scope-level += "{" ;
767 }
768 else if [ MATCH "^[^\\}]*([\\}])[$(ws)]*$" : $(syntax-block) ]
769 {
770 scope-level = $(scope-level[2-]) ;
771 }
772 }
773
774 return true ;
775 }
776 }
777
778
779 # Scan the arguments of a rule.
780 #
781 local rule scan-rule-arguments (
782 var # The name of the variable to extract from.
783 )
784 {
785 local arg-syntax = ;
786 local token = [ extract-token $(var) ] ;
787 while $(token) != "(" && $(token) != "{"
788 {
789 token = [ extract-token $(var) ] ;
790 }
791 if $(token) != "{"
792 {
793 token = [ extract-token $(var) ] ;
794 }
795 local arg-signature = ;
796 while $(token) != ")" && $(token) != "{"
797 {
798 local arg-name = ;
799 local arg-qualifier = " " ;
800 local arg-doc = ;
801 if $(token) = ":"
802 {
803 arg-signature += $(token) ;
804 token = [ extract-token $(var) ] ;
805 }
806 arg-name = $(token) ;
807 arg-signature += $(token) ;
808 token = [ extract-token $(var) ] ;
809 if [ MATCH "^([\\*\\+\\?])" : $(token) ]
810 {
811 arg-qualifier = $(token) ;
812 arg-signature += $(token) ;
813 token = [ extract-token $(var) ] ;
814 }
815 if $(token) = ":"
816 {
817 arg-signature += $(token) ;
818 token = [ extract-token $(var) ] ;
819 }
820 if [ MATCH "^(#)" : $(token) ]
821 {
822 $(var) = $(token) $($(var)) ;
823 arg-doc = [ extract-comment $(var) ] ;
824 token = [ extract-token $(var) ] ;
825 }
826 set-argument-doc $(arg-name) $(arg-qualifier) $(rule-name) $(module-name) : $(arg-doc) ;
827 }
828 while $(token) != "{"
829 {
830 token = [ extract-token $(var) ] ;
831 }
832 $(var) = "{" $($(var)) ;
833 arg-signature ?= "" ;
834 return $(arg-signature) ;
835 }
836
837
838 # Scan for a variable declaration.
839 #
840 local rule scan-variable (
841 syntax ? # The first part of the text which contains the variable declaration.
842 : var # The name of the variable to extract from.
843 )
844 {
845 # [1] = name, [2] = value(s)
846 local var-parts =
847 [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]+([\\?\\=]*)[$(ws)]+([^\\;]*)\\;" : $(syntax) ] ;
848 if $(var-parts)
849 {
850 local value = [ MATCH "^(.*)[ ]$" : $(var-parts[3-]:J=" ") ] ;
851 local default-value = "" ;
852 local initial-valie = "" ;
853 if $(var-parts[2]) = "?="
854 {
855 default-value = $(value) ;
856 default-value ?= "(empty)" ;
857 }
858 else
859 {
860 initial-value = $(value) ;
861 initial-value ?= "(empty)" ;
862 }
863 if $(comment-block)
864 {
865 set-variable-doc $(var-parts[1]) $(default-value) $(initial-value) $(module-name) : $(comment-block) ;
866 }
867 return true ;
868 }
869 }
870
871
872 # Scan a class declaration.
873 #
874 local rule scan-class (
875 syntax ? # The syntax text for the class declaration.
876 )
877 {
878 # [1] = class?, [2] = name, [3] = superclass
879 local class-parts =
880 [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]+([^$(ws)]+)[$(ws)]+:*[$(ws)]*([^$(ws);]*)" : $(syntax) ] ;
881 if $(class-parts[1]) = "class" || $(class-parts[1]) = "class.class"
882 {
883 set-class-doc $(class-parts[2]) $(module-name) : $(class-parts[3]) ;
884 }
885 }
886
887
888 # Scan a module file for documentation comments. This also invokes any actions
889 # assigned to the module. The actions are the rules that do the actual output of
890 # the documentation. This rule is invoked as the header scan rule for the module
891 # file.
892 #
893 rule scan-module (
894 target # The module file.
895 : text * # The text in the file, one item per line.
896 : action * # Rule to call to output docs for the module.
897 )
898 {
899 if $(.option.debug) { ECHO "HELP:" scanning module target '$(target)' ; }
900 local module-name = $(target:B) ;
901 local module-documented = ;
902 local comment-block = ;
903 local syntax-block = ;
904 # This is a hack because we can not get the line of a file if it happens to
905 # not have a new-line termination.
906 text += "}" ;
907 while $(text)
908 {
909 comment-block = [ extract-comment text ] ;
910 syntax-block = [ extract-syntax text ] ;
911 if $(.option.debug)
912 {
913 ECHO "HELP:" comment block; '$(comment-block)' ;
914 ECHO "HELP:" syntax block; '$(syntax-block)' ;
915 }
916 if [ scan-rule $(syntax-block) : text ] { }
917 else if [ scan-variable $(syntax-block) : text ] { }
918 else if [ scan-class $(syntax-block) ] { }
919 else if [ MATCH .*([cC]opyright).* : $(comment-block:J=" ") ]
920 {
921 # mark as the copy for the module.
922 set-module-copyright $(module-name) : $(comment-block) ;
923 }
924 else if $(action[1]) in "print-help-project" "print-help-config"
925 && ! $(jamfile<$(target)>.docs)
926 {
927 # special module docs for the project jamfile.
928 jamfile<$(target)>.docs = $(comment-block) ;
929 }
930 else if ! $(module-documented)
931 {
932 # document the module.
933 set-module-doc $(module-name) : $(comment-block) ;
934 module-documented = true ;
935 }
936 }
937 if $(action)
938 {
939 $(action[1]) $(module-name) : $(action[2-]) ;
940 }
941 }
942
943
944 # Import scan-module to global scope, so that it is available during header
945 # scanning phase.
946 #
947 IMPORT $(__name__) : scan-module : : doc.scan-module ;
948
949
950 # Read in a file using the SHELL builtin and return the individual lines as
951 # would be done for header scanning.
952 #
953 local rule read-file (
954 file # The file to read in.
955 )
956 {
957 file = [ path.native [ path.root [ path.make $(file) ] [ path.pwd ] ] ] ;
958 if ! $(.file<$(file)>.lines)
959 {
960 local content ;
961 switch [ modules.peek : OS ]
962 {
963 case NT :
964 content = [ SHELL "TYPE \"$(file)\"" ] ;
965
966 case * :
967 content = [ SHELL "cat \"$(file)\"" ] ;
968 }
969 local lines ;
970 local nl = "
971 " ;
972 local << = "([^$(nl)]*)[$(nl)](.*)" ;
973 local line+ = [ MATCH "$(<<)" : "$(content)" ] ;
974 while $(line+)
975 {
976 lines += $(line+[1]) ;
977 line+ = [ MATCH "$(<<)" : "$(line+[2])" ] ;
978 }
979 .file<$(file)>.lines = $(lines) ;
980 }
981 return $(.file<$(file)>.lines) ;
982 }
983
984
985 # Add a scan action to perform to generate the help documentation. The action
986 # rule is passed the name of the module as the first argument. The second
987 # argument(s) are optional and passed directly as specified here.
988 #
989 local rule do-scan (
990 modules + # The modules to scan and perform the action on.
991 : action * # The action rule, plus the secondary arguments to pass to the action rule.
992 )
993 {
994 if $(help-output) = text
995 {
996 print.output $(help-output-file).txt plain ;
997 ALWAYS $(help-output-file).txt ;
998 DEPENDS all : $(help-output-file).txt ;
999 }
1000 if $(help-output) = html
1001 {
1002 print.output $(help-output-file).html html ;
1003 ALWAYS $(help-output-file).html ;
1004 DEPENDS all : $(help-output-file).html ;
1005 }
1006 for local module-file in $(modules[1--2])
1007 {
1008 scan-module $(module-file) : [ read-file $(module-file) ] ;
1009 }
1010 scan-module $(modules[-1]) : [ read-file $(modules[-1]) ] : $(action) ;
1011 }