2 # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
6 dir
=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
8 # Note that the version has a trailing + on unreleased versions
9 set autosetup
(version
) 0.6.9
11 # Can be set to 1 to debug early-init problems
12 set autosetup
(debug
) [expr {"--debug" in $argv}]
14 ##################################################################
16 # Main flow of control, option handling
19 global autosetup define
21 # There are 3 potential directories involved:
22 # 1. The directory containing autosetup (this script)
23 # 2. The directory containing auto.def
24 # 3. The current directory
26 # From this we need to determine:
27 # a. The path to this script (and related support files)
28 # b. The path to auto.def
29 # c. The build directory, where output files are created
31 # This is also complicated by the fact that autosetup may
32 # have been run via the configure wrapper ([getenv WRAPPER] is set)
35 # a. This script is $::argv0
36 # => dir, prog, exe, libdir
37 # b. auto.def is in the directory containing the configure wrapper,
38 # otherwise it is in the current directory.
40 # c. The build directory is the current directory
43 # 'misc' is needed before we can do anything, so set a temporary libdir
44 # in case this is the development version
45 set autosetup
(libdir
) [file dirname $
::argv0
]/lib
49 set autosetup
(dir
) [realdir
[file dirname [realpath $
::argv0
]]]
50 set autosetup
(prog
) [file join $autosetup(dir
) [file tail $
::argv0
]]
51 set autosetup
(exe
) [getenv WRAPPER
$autosetup(prog
)]
52 if {$autosetup(installed
)} {
53 set autosetup
(libdir
) $autosetup(dir
)
55 set autosetup
(libdir
) [file join $autosetup(dir
) lib
]
57 autosetup_add_dep
$autosetup(prog
)
60 if {[getenv WRAPPER
""] eq
""} {
62 set autosetup
(srcdir
) [pwd]
64 # Invoked via the configure wrapper
65 set autosetup
(srcdir
) [file-normalize
[file dirname $autosetup(exe
)]]
67 set autosetup
(autodef
) [relative-path
$autosetup(srcdir
)/auto.def
]
70 set autosetup
(builddir
) [pwd]
72 set autosetup
(argv
) $argv
73 set autosetup
(cmdline
) {}
74 # options is a list of known options
75 set autosetup
(options
) {}
76 # optset is a dictionary of option values set by the user based on getopt
77 set autosetup
(optset
) {}
78 # optdefault is a dictionary of default values
79 set autosetup
(optdefault
) {}
80 # options-defaults is a dictionary of overrides for default values for options
81 set autosetup
(options-defaults
) {}
82 set autosetup
(optionhelp
) {}
83 set autosetup
(showhelp
) 0
90 # At the is point we don't know what is a valid option
91 # We simply parse anything that looks like an option
92 set autosetup
(getopt
) [getopt argv
]
96 help:=local => "display help and options. Optionally specify a module name, such as --help=system"
97 licence license
=> "display the autosetup license"
98 version
=> "display the version of autosetup"
99 ref
:=text manual
:=text
100 reference
:=text
=> "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
101 debug
=> "display debugging output as autosetup runs"
102 install:=.
=> "install autosetup to the current or given directory"
104 if {$autosetup(installed
)} {
105 # hidden options so we can produce a nice error
111 sysinstall
:path
=> "install standalone autosetup to the given directory (e.g.: /usr/local)"
115 force init
:=help => "create initial auto.def, etc. Use --init=help for known types"
116 # Undocumented options
124 if {[opt-bool version
]} {
125 puts
$autosetup(version
)
129 # autosetup --conf=alternate-auto.def
130 if {[opt-str conf o
]} {
131 set autosetup
(autodef
) $o
134 # Debugging output (set this early)
135 incr autosetup
(debug
) [opt-bool debug
]
136 incr autosetup
(force
) [opt-bool force
]
137 incr autosetup
(msg-quiet
) [opt-bool quiet
]
138 incr autosetup
(msg-timing
) [opt-bool timing
]
140 # If the local module exists, source it now to allow for
141 # project-local customisations
142 if {[file exists
$autosetup(libdir
)/local.tcl
]} {
146 # Now any auto-load modules
147 autosetup_load_auto_modules
149 if {[opt-str
help o
]} {
150 incr autosetup
(showhelp
)
155 if {[opt-bool licence license
]} {
157 autosetup_show_license
161 if {[opt-str
{manual ref reference
} o
]} {
163 autosetup_reference
$o
166 # Allow combining --install and --init
168 if {[opt-str
install o
]} {
174 if {[opt-str init o
]} {
183 if {[opt-str sysinstall o
]} {
185 autosetup_install
$o 1
189 if {![file exists
$autosetup(autodef
)]} {
190 # Check for invalid option first
192 user-error
"No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
195 # Parse extra arguments into autosetup(cmdline)
197 if {[regexp
{([^
=]*)=(.
*)} $arg -> n v
]} {
198 dict
set autosetup
(cmdline
) $n $v
201 user-error
"Unexpected parameter: $arg"
205 autosetup_add_dep
$autosetup(autodef
)
207 define CONFIGURE_OPTS
""
208 foreach arg
$autosetup(argv
) {
209 define-append CONFIGURE_OPTS
[quote-if-needed
$arg]
211 define AUTOREMAKE
[file-normalize
$autosetup(exe
)]
212 define-append AUTOREMAKE
[get-define CONFIGURE_OPTS
]
215 # Log how we were invoked
216 configlog
"Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
217 configlog
"Tclsh: [info nameofexecutable]"
219 # Note that auto.def is *not* loaded in the global scope
220 source $autosetup(autodef
)
222 # Could warn here if options {} was not specified
226 if {$autosetup(debug
)} {
227 msg-result
"Writing all defines to config.log"
228 configlog
"================ defines ======================"
229 foreach n
[lsort
[array names define
]] {
230 configlog
"define $n $define($n)"
237 # @opt-bool ?-nodefault? option ...
239 # Check each of the named, boolean options and if any have been explicitly enabled
240 # or disabled by the user, return 1 or 0 accordingly.
242 # If the option was specified more than once, the last value wins.
243 # e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
245 # If no value was specified by the user, returns the default value for the
246 # first option. If '-nodefault' is given, this behaviour changes and
247 # -1 is returned instead.
249 proc opt-bool
{args
} {
251 if {[lindex
$args 0] eq
"-nodefault"} {
253 set args
[lrange
$args 1 end
]
255 option-check-names
{*}$args
258 if {[dict exists $
::autosetup
(optset
) $opt]} {
259 return [dict get $
::autosetup
(optset
) $opt]
266 # Default value is the default for the first option
267 return [dict get $
::autosetup
(optdefault
) [lindex
$args 0]]
270 # @opt-val optionlist ?default=""?
272 # Returns a list containing all the values given for the non-boolean options in '$optionlist'.
273 # There will be one entry in the list for each option given by the user, including if the
274 # same option was used multiple times.
276 # If no options were set, '$default' is returned (exactly, not as a list).
278 # Note: For most use cases, 'opt-str' should be preferred.
280 proc opt-val
{names
{default
""}} {
281 option-check-names
{*}$names
284 if {[dict exists $
::autosetup
(optset
) $opt]} {
285 lappend result
{*}[dict get $
::autosetup
(optset
) $opt]
288 if {[info exists result
]} {
294 # @opt-str optionlist varname ?default?
296 # Sets '$varname' in the callers scope to the value for one of the given options.
298 # For the list of options given in '$optionlist', if any value is set for any option,
299 # the option value is taken to be the *last* value of the last option (in the order given).
301 # If no option was given, and a default was specified with 'options-defaults',
302 # that value is used.
304 # If no 'options-defaults' value was given and '$default' was given, it is used.
306 # If none of the above provided a value, no value is set.
308 # The return value depends on whether '$default' was specified.
309 # If it was, the option value is returned.
310 # If it was not, 1 is returns if a value was set, or 0 if not.
312 # Typical usage is as follows:
314 ## if {[opt-str {myopt altname} o]} {
315 ## do something with $o
319 ## define myname [opt-str {myopt altname} o "/usr/local"]
321 proc opt-str
{names varname args
} {
324 option-check-names
{*}$names
327 if {[llength
$args]} {
328 # A default was given, so always return the string value of the option
329 set default
[lindex
$args 0]
332 # No default, so return 0 or 1 to indicate if a value was found
337 if {[dict exists $
::autosetup
(optset
) $opt]} {
338 set result
[lindex
[dict get $
::autosetup
(optset
) $opt] end
]
342 if {![info exists result
]} {
343 # No user-specified value. Has options-defaults been set?
345 if {[dict exists $
::autosetup
(options-defaults
) $opt]} {
346 set result
[dict get
$autosetup(options-defaults
) $opt]
351 if {[info exists result
]} {
367 proc option-check-names
{args
} {
369 if {$o ni $
::autosetup
(options
)} {
370 autosetup-error
"Request for undeclared option --$o"
375 # Parse the option definition in $opts and update
376 # ::autosetup(setoptions) and ::autosetup(optionhelp) appropriately
378 proc options-add
{opts
{header
""}} {
381 # First weed out comment lines
383 foreach line
[split $opts \n] {
384 if {![string match
"#*" [string trimleft
$line]]} {
385 append realopts
$line \n
390 for {set i
0} {$i < [llength
$opts]} {incr i
} {
391 set opt
[lindex
$opts $i]
392 if {[string match
=* $opt]} {
393 # This is a special heading
394 lappend autosetup
(optionhelp
) $opt ""
398 unset -nocomplain defaultvalue equal value
400 #puts "i=$i, opt=$opt"
401 regexp
{^
([^
:=]*)(:)?
(=)?
(.
*)$
} $opt -> name colon equal value
402 if {$name in $autosetup(options
)} {
403 autosetup-error
"Option $name already specified"
406 #puts "$opt => $name $colon $equal $value"
408 # Find the corresponding value in the user options
409 # and set the default if necessary
410 if {[string match
"-*" $opt]} {
411 # This is a documentation-only option, like "-C <dir>"
413 } elseif
{$colon eq
""} {
415 lappend autosetup
(options
) $name
418 if {[dict exists
$autosetup(options-defaults
) $name]} {
419 # A default was specified with options-defaults, so use it
420 set value
[dict get
$autosetup(options-defaults
) $name]
424 set opthelp
"--disable-$name"
426 set opthelp
"--$name"
433 set defaultvalue
$value
434 dict
set autosetup
(optdefault
) $name $defaultvalue
436 if {[dict exists
$autosetup(getopt
) $name]} {
437 # The option was specified by the user. Look at the last value.
438 lassign
[lindex
[dict get
$autosetup(getopt
) $name] end
] type setvalue
439 if {$type eq
"str"} {
440 # Can we convert the value to a boolean?
441 if {$setvalue in {1 enabled
yes}} {
443 } elseif
{$setvalue in {0 disabled no
}} {
446 user-error
"Boolean option $name given as --$name=$setvalue"
449 dict
set autosetup
(optset
) $name $setvalue
450 #puts "Found boolean option --$name=$setvalue"
454 lappend autosetup
(options
) $name
457 # Was ":name=default" given?
458 # If so, set $value to the display name and $defaultvalue to the default
459 # (This is the preferred way to set a default value for a string option)
460 if {[regexp
{^
([^
=]+)=(.
*)$
} $value -> value defaultvalue
]} {
461 dict
set autosetup
(optdefault
) $name $defaultvalue
465 # Maybe override the default value
466 if {[dict exists
$autosetup(options-defaults
) $name]} {
467 # A default was specified with options-defaults, so use it
468 set defaultvalue
[dict get
$autosetup(options-defaults
) $name]
469 dict
set autosetup
(optdefault
) $name $defaultvalue
470 } elseif
{![info exists defaultvalue
]} {
471 # For backward compatibility, if ":name" was given, use name as both
472 # the display text and the default value, but only if the user
473 # specified the option without the value
474 set defaultvalue
$value
478 # String option with optional value
479 set opthelp
"--$name?=$value?"
481 # String option with required value
482 set opthelp
"--$name=$value"
485 # Get the values specified by the user
486 if {[dict exists
$autosetup(getopt
) $name]} {
489 foreach pair
[dict get
$autosetup(getopt
) $name] {
490 lassign
$pair type setvalue
491 if {$type eq
"bool" && $setvalue} {
493 user-error
"Option --$name requires a value"
495 # If given as a boolean, use the default value
496 set setvalue
$defaultvalue
498 lappend listvalue
$setvalue
501 #puts "Found string option --$name=$listvalue"
502 dict
set autosetup
(optset
) $name $listvalue
506 # Now create the help for this option if appropriate
507 if {[lindex
$opts $i+1] eq
"=>"} {
508 set desc
[lindex
$opts $i+2]
509 if {[info exists defaultvalue
]} {
510 set desc
[string map
[list @default@
$defaultvalue] $desc]
512 #string match \n* $desc
514 lappend autosetup
(optionhelp
) $header ""
517 # A multi-line description
518 lappend autosetup
(optionhelp
) $opthelp $desc
524 # @module-options optionlist
526 # Like 'options', but used within a module.
527 proc module-options
{opts
} {
529 if {$
::autosetup
(showhelp
) > 1 && [llength
$opts]} {
530 set header
"Module Options:"
532 options-add
$opts $header
534 if {$
::autosetup
(showhelp
)} {
535 # Ensure that the module isn't executed on --help
536 # We are running under eval or source, so use break
537 # to prevent further execution
538 #return -code break -level 2
544 expr {$a > $b ?
$a : $b}
547 proc options-wrap-desc
{text length firstprefix nextprefix initial
} {
549 set space
$firstprefix
550 foreach word
[split $text] {
551 set word
[string trim
$word]
555 if {$len && [string length
$space$word] + $len >= $length} {
558 set space
$nextprefix
560 incr len
[string length
$space$word]
561 puts
-nonewline $space$word
569 proc options-show
{} {
570 # Determine the max option width
572 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
573 if {[string match
=* $opt] ||
[string match
\n* $desc]} {
576 set max
[max
$max [string length
$opt]]
578 set indent
[string repeat
" " [expr $max+4]]
579 set cols
[getenv COLUMNS
80]
581 lassign
[exec stty size
] rows cols
585 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
586 if {[string match
=* $opt]} {
587 puts
[string range
$opt 1 end
]
590 puts
-nonewline " [format %-${max}s $opt]"
591 if {[string match
\n* $desc]} {
594 options-wrap-desc
[string trim
$desc] $cols " " $indent [expr $max + 2]
599 # @options optionspec
601 # Specifies configuration-time options which may be selected by the user
602 # and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
603 # of options specifications separated by newlines, as follows:
605 # A boolean option is of the form:
607 ## name[=0|1] => "Description of this boolean option"
609 # The default is 'name=0', meaning that the option is disabled by default.
610 # If 'name=1' is used to make the option enabled by default, the description should reflect
611 # that with text like "Disable support for ...".
613 # An argument option (one which takes a parameter) is of the form:
615 ## name:[=]value => "Description of this option"
617 # If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
618 # If the 'name:=value' form is used, the value is optional and the given value is used as the default
619 # if it is not provided.
621 # The description may contain '@default@', in which case it will be replaced with the default
622 # value for the option (taking into account defaults specified with 'options-defaults'.
624 # Undocumented options are also supported by omitting the '=> description'.
625 # These options are not displayed with '--help' and can be useful for internal options or as aliases.
627 # For example, '--disable-lfs' is an alias for '--disable=largefile':
629 ## lfs=1 largefile=1 => "Disable large file support"
631 proc options
{optlist
} {
632 # Allow options as a list or args
633 options-add
$optlist "Local Options:"
635 if {$
::autosetup
(showhelp
)} {
640 # Check for invalid options
641 if {[opt-bool option-checking
]} {
642 foreach o
[dict keys $
::autosetup
(getopt
)] {
643 if {$o ni $
::autosetup
(options
)} {
644 user-error
"Unknown option --$o"
650 # @options-defaults dictionary
652 # Specifies a dictionary of options and a new default value for each of those options.
653 # Use before any 'use' statements in 'auto.def' to change the defaults for
654 # subsequently included modules.
655 proc options-defaults
{dict
} {
656 foreach
{n v
} $dict {
657 dict
set ::autosetup
(options-defaults
) $n $v
661 proc config_guess
{} {
662 if {[file-isexec $
::autosetup
(dir
)/autosetup-config.guess
]} {
663 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/autosetup-config.guess
} alias]} {
668 configlog
"No autosetup-config.guess, so using uname"
669 string tolower
[exec uname
-p]-unknown-[exec uname
-s][exec uname
-r]
673 proc config_sub
{alias} {
674 if {[file-isexec $
::autosetup
(dir
)/autosetup-config.sub
]} {
675 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/autosetup-config.sub
$alias} alias]} {
682 # @define name ?value=1?
684 # Defines the named variable to the given value.
685 # These (name, value) pairs represent the results of the configuration check
686 # and are available to be subsequently checked, modified and substituted.
688 proc define
{name
{value
1}} {
689 set ::define
($name) $value
690 #dputs "$name <= $value"
695 # Undefine the named variable.
697 proc undefine
{name
} {
698 unset -nocomplain ::define
($name)
699 #dputs "$name <= <undef>"
702 # @define-append name value ...
704 # Appends the given value(s) to the given "defined" variable.
705 # If the variable is not defined or empty, it is set to '$value'.
706 # Otherwise the value is appended, separated by a space.
707 # Any extra values are similarly appended.
708 # If any value is already contained in the variable (as a substring) it is omitted.
710 proc define-append
{name args
} {
711 if {[get-define
$name ""] ne
""} {
718 foreach str
[split $
::define
($name) " "] {
724 append
::define
($name) " " $arg
728 set ::define
($name) [join $args]
730 #dputs "$name += [join $args] => $::define($name)"
733 # @get-define name ?default=0?
735 # Returns the current value of the "defined" variable, or '$default'
738 proc get-define
{name
{default
0}} {
739 if {[info exists
::define
($name)]} {
740 #dputs "$name => $::define($name)"
741 return $
::define
($name)
743 #dputs "$name => $default"
749 # Returns 1 if the given variable is defined.
751 proc is-defined
{name
} {
752 info exists
::define
($name)
755 # @is-define-set name
757 # Returns 1 if the given variable is defined and is set
758 # to a value other than "" or 0
760 proc is-define-set
{name
} {
761 if {[get-define
$name] in {0 ""}} {
769 # Returns a dictionary (name, value list) of all defined variables.
771 # This is suitable for use with 'dict', 'array set' or 'foreach'
772 # and allows for arbitrary processing of the defined variables.
774 proc all-defines
{} {
779 # @get-env name default
781 # If '$name' was specified on the command line, return it.
782 # Otherwise if '$name' was set in the environment, return it.
783 # Otherwise return '$default'.
785 proc get-env
{name default
} {
786 if {[dict exists $
::autosetup
(cmdline
) $name]} {
787 return [dict get $
::autosetup
(cmdline
) $name]
789 getenv
$name $default
794 # Returns 1 if '$name' was specified on the command line or in the environment.
795 # Note that an empty environment variable is not considered to be set.
797 proc env-is-set
{name
} {
798 if {[dict exists $
::autosetup
(cmdline
) $name]} {
801 if {[getenv
$name ""] ne
""} {
807 # @readfile filename ?default=""?
809 # Return the contents of the file, without the trailing newline.
810 # If the file doesn't exist or can't be read, returns '$default'.
812 proc readfile
{filename
{default_value
""}} {
813 set result
$default_value
815 set f
[open
$filename]
816 set result
[read -nonewline $f]
822 # @writefile filename value
824 # Creates the given file containing '$value'.
825 # Does not add an extra newline.
827 proc writefile
{filename value
} {
828 set f
[open
$filename w
]
829 puts
-nonewline $f $value
833 proc quote-if-needed
{str
} {
834 if {[string match
{*[\" ]*} $str]} {
835 return \"[string map
[list
\" \\" \\ \\\\] $str]\"
840 proc quote-argv {argv} {
843 lappend args [quote-if-needed $arg]
848 # @list-non-empty list
850 # Returns a copy of the given list with empty elements removed
851 proc list-non-empty {list} {
861 # @find-executable-path name
863 # Searches the path for an executable with the given name.
864 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
865 # in which case the parameters are ignored.
866 # The full path to the executable if found, or "" if not found.
867 # Returns 1 if found, or 0 if not.
869 proc find-executable-path {name} {
870 # Ignore any parameters
871 set name [lindex $name 0]
872 # The empty string is never a valid executable
874 foreach p [split-path] {
875 dputs "Looking
for $name in $p"
876 set exec [file join $p $name]
877 if {[file-isexec $exec]} {
878 dputs "Found
$name -> $exec"
886 # @find-executable name
888 # Searches the path for an executable with the given name.
889 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
890 # in which case the parameters are ignored.
891 # Returns 1 if found, or 0 if not.
893 proc find-executable {name} {
894 if {[find-executable-path $name] eq {}} {
900 # @find-an-executable ?-required? name ...
902 # Given a list of possible executable names,
903 # searches for one of these on the path.
905 # Returns the name found, or "" if none found.
906 # If the first parameter is '-required', an error is generated
907 # if no executable is found.
909 proc find-an-executable {args} {
911 if {[lindex $args 0] eq "-required"} {
912 set args [lrange $args 1 end]
916 if {[find-executable $name]} {
921 if {[llength $args] == 1} {
922 user-error "failed to
find: [join $args]"
924 user-error "failed to
find one of
: [join $args]"
932 # Writes the given message to the configuration log, 'config.log'.
934 proc configlog {msg} {
935 if {![info exists ::autosetup(logfh)]} {
936 set ::autosetup(logfh) [open config.log w]
938 puts $::autosetup(logfh) $msg
943 # Writes the message with no newline to stdout.
945 proc msg-checking {msg} {
946 if {$::autosetup(msg-quiet) == 0} {
949 set ::autosetup(msg-checking) 1
955 # Writes the message to stdout.
957 proc msg-result {msg} {
958 if {$::autosetup(msg-quiet) == 0} {
961 set ::autosetup(msg-checking) 0
966 # @msg-quiet command ...
968 # 'msg-quiet' evaluates it's arguments as a command with output
969 # from 'msg-checking' and 'msg-result' suppressed.
971 # This is useful if a check needs to run a subcheck which isn't
972 # of interest to the user.
973 proc msg-quiet {args} {
974 incr ::autosetup(msg-quiet)
975 set rc [uplevel 1 $args]
976 incr ::autosetup(msg-quiet) -1
980 # Will be overridden by 'use misc'
981 proc error-stacktrace {msg} {
985 proc error-location {msg} {
989 ##################################################################
994 if {$::autosetup(debug)} {
999 ##################################################################
1001 # User and system warnings and errors
1003 # Usage errors such as wrong command line options
1007 # Indicate incorrect usage to the user, including if required components
1008 # or features are not found.
1009 # 'autosetup' exits with a non-zero return code.
1011 proc user-error {msg} {
1013 puts stderr "Error
: $msg"
1014 puts stderr "Try
: '[file tail $::autosetup(exe)] --help' for options
"
1020 # Output the given message to stderr.
1022 proc user-notice {msg} {
1023 lappend ::autosetup(notices) $msg
1026 # Incorrect usage in the auto.def file. Identify the location.
1027 proc autosetup-error {msg} {
1028 autosetup-full-error [error-location $msg]
1031 # Like autosetup-error, except $msg is the full error message.
1032 proc autosetup-full-error {msg} {
1038 proc show-notices {} {
1039 if {$::autosetup(msg-checking)} {
1041 set ::autosetup(msg-checking) 0
1044 if {[info exists ::autosetup(notices)]} {
1045 puts stderr [join $::autosetup(notices) \n]
1046 unset ::autosetup(notices)
1050 proc maybe-show-timestamp {} {
1051 if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
1052 puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
1056 # @autosetup-require-version required
1058 # Checks the current version of 'autosetup' against '$required'.
1059 # A fatal error is generated if the current version is less than that required.
1061 proc autosetup-require-version {required} {
1062 if {[compare-versions $::autosetup(version) $required] < 0} {
1063 user-error "autosetup version
$required is required
, but this is $
::autosetup
(version
)"
1067 proc autosetup_version {} {
1068 return "autosetup v$
::autosetup
(version
)"
1071 ##################################################################
1073 # Directory/path handling
1076 proc realdir {dir} {
1084 # Follow symlinks until we get to something which is not a symlink
1085 proc realpath {path} {
1088 set path [file readlink $path]
1097 # Convert absolute path, $path into a path relative
1098 # to the given directory (or the current dir, if not given).
1100 proc relative-path {path {pwd {}}} {
1105 set path [file-normalize $path]
1109 set pwd [file-normalize $pwd]
1112 if {$path eq $pwd} {
1116 # Try to make the filename relative to the current dir
1117 foreach p [split $pwd /] f [split $path /] {
1125 # Add .. for sibling or parent dir
1133 if {$same == 1 || [llength $prefix] > 3} {
1137 file join [join $prefix /] [join $newf /]
1140 # Add filename as a dependency to rerun autosetup
1141 # The name will be normalised (converted to a full path)
1143 proc autosetup_add_dep {filename} {
1144 lappend ::autosetup(deps) [file-normalize $filename]
1147 ##################################################################
1149 # Library module support
1154 # Load the given library modules.
1155 # e.g. 'use cc cc-shared'
1157 # Note that module 'X' is implemented in either 'autosetup/X.tcl'
1158 # or 'autosetup/X/init.tcl'
1160 # The latter form is useful for a complex module which requires additional
1161 # support file. In this form, '$::usedir' is set to the module directory
1162 # when it is loaded.
1165 global autosetup libmodule modsource
1167 set dirs [list $autosetup(libdir)]
1168 if {[info exists autosetup(srcdir)]} {
1169 lappend dirs $autosetup(srcdir)/autosetup
1172 if {[info exists libmodule($m)]} {
1176 if {[info exists modsource(${m}.tcl)]} {
1177 automf_load eval $modsource(${m}.tcl)
1179 set locs [list ${m}.tcl ${m}/init.tcl]
1183 set source $dir/$loc
1184 if {[file exists $source]} {
1194 # For the convenience of the "use
" source, point to the directory
1195 # it is being loaded from
1196 set ::usedir [file dirname $source]
1197 automf_load source $source
1198 autosetup_add_dep $source
1200 autosetup-error "use
: No such module
: $m"
1206 proc autosetup_load_auto_modules {} {
1207 global autosetup modsource
1208 # First load any embedded auto modules
1209 foreach mod [array names modsource *.auto] {
1210 automf_load eval $modsource($mod)
1212 # Now any external auto modules
1213 foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
1214 automf_load source $file
1218 # Load module source in the global scope by executing the given command
1219 proc automf_load {args} {
1220 if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
1221 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
1226 set autosetup(exe) $::argv0
1227 set autosetup(istcl) 1
1228 set autosetup(start) [clock millis]
1229 set autosetup(installed) 0
1230 set autosetup(sysinstall) 0
1231 set autosetup(msg-checking) 0
1232 set autosetup(msg-quiet) 0
1233 set autosetup(inittypes) {}
1235 # Embedded modules are inserted below here
1236 set autosetup(installed) 1
1237 set autosetup(sysinstall) 0
1238 # ----- @module asciidoc-formatting.tcl -----
1240 set modsource(asciidoc-formatting.tcl) {
1241 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1242 # All rights reserved
1244 # Module which provides text formatting
1250 regsub -all "\
[ \t\n\
]+" [string trim $text] " "
1253 underline [para $text] =
1261 foreach line [parse_code_block $text] {
1266 proc codelines {lines} {
1267 foreach line $lines {
1275 proc underline {text char} {
1276 regexp "^
(\
[ \t\
]*)(.
*)" $text -> indent words
1278 puts $indent[string repeat $char [string length $words]]
1280 proc section {text} {
1281 underline "[para
$text]" -
1284 proc subsection {text} {
1288 proc bullet {text} {
1289 puts "* [para
$text]"
1291 proc indent {text} {
1295 proc defn {first args} {
1302 set defn [string trim [join $args \n]]
1303 regsub -all "\n\n" $defn "\n ::\n" defn
1308 # ----- @module formatting.tcl -----
1310 set modsource(formatting.tcl) {
1311 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1312 # All rights reserved
1314 # Module which provides common text formatting
1316 # This is designed for documentation which looks like:
1323 # In the second case, we need to work out the indenting
1324 # and strip it from all lines but preserve the remaining indenting.
1325 # Note that all lines need to be indented with the same initial
1328 # Returns a list of lines with the indenting removed.
1330 proc parse_code_block {text} {
1331 # If the text begins with newline, take the following text,
1332 # otherwise just return the original
1333 if {![regexp "^
\n(.
*)" $text -> text]} {
1334 return [list [string trim $text]]
1337 # And trip spaces off the end
1338 set text [string trimright $text]
1341 # Examine each line to determine the minimum indent
1342 foreach line [split $text \n] {
1344 # Ignore empty lines for the indent calculation
1347 regexp "^
(\
[ \t\
]*)" $line -> indent
1348 set len [string length $indent]
1354 # Now make a list of lines with this indent removed
1356 foreach line [split $text \n] {
1357 lappend lines [string range $line $min end]
1365 # ----- @module getopt.tcl -----
1367 set modsource(getopt.tcl) {
1368 # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
1369 # All rights reserved
1371 # Simple getopt module
1373 # Parse everything out of the argv list which looks like an option
1374 # Everything which doesn't look like an option, or is after --, is left unchanged
1375 # Understands --enable-xxx as a synonym for --xxx to enable the boolean option xxx.
1376 # Understands --disable-xxx to disable the boolean option xxx.
1378 # The returned value is a dictionary keyed by option name
1379 # Each value is a list of {type value} ... where type is "bool
" or "str
".
1380 # The value for a boolean option is 0 or 1. The value of a string option is the value given.
1381 proc getopt {argvname} {
1382 upvar $argvname argv
1387 for {set i 0} {$i < [llength $argv]} {incr i} {
1388 set arg [lindex $argv $i]
1395 lappend nargv {*}[lrange $argv $i end]
1399 if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
1401 dict lappend opts $name [list str $value]
1402 } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1403 if {$prefix in {enable- ""}} {
1408 dict lappend opts $name [list bool $value]
1414 #puts "getopt
: argv
=[join $argv] => [join $nargv]"
1415 #array set getopt $opts
1424 # ----- @module help.tcl -----
1426 set modsource(help.tcl) {
1427 # Copyright (c) 2010 WorkWare Systems http://workware.net.au/
1428 # All rights reserved
1430 # Module which provides usage, help and the command reference
1432 proc autosetup_help {what} {
1435 puts "Usage
: [file tail $
::autosetup
(exe
)] \
[options\
] \
[settings\
]\n"
1436 puts "This is
[autosetup_version
], a build environment
\"autoconfigurator
\""
1437 puts "See the documentation online
at http
://msteveb.github.com
/autosetup
/\n"
1439 if {$what eq "local"} {
1440 if {[file exists $::autosetup(autodef)]} {
1441 # This relies on auto.def having a call to 'options'
1442 # which will display options and quit
1443 source $::autosetup(autodef)
1448 incr ::autosetup(showhelp)
1449 if {[catch {use $what}]} {
1450 user-error "Unknown module
: $what"
1458 proc autosetup_show_license {} {
1459 global modsource autosetup
1462 if {[info exists modsource(LICENSE)]} {
1463 puts $modsource(LICENSE)
1466 foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
1467 set path [file join $dir LICENSE]
1468 if {[file exists $path]} {
1469 puts [readfile $path]
1473 puts "LICENSE not found
"
1476 # If not already paged and stdout is a tty, pipe the output through the pager
1477 # This is done by reinvoking autosetup with --nopager added
1479 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1481 exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
1483 if {[dict get $opts -errorcode] eq "NONE
"} {
1484 # an internal/exec error
1493 # Outputs the autosetup references in one of several formats
1494 proc autosetup_reference {{type text}} {
1498 switch -glob -- $type {
1499 wiki {use wiki-formatting}
1500 ascii* {use asciidoc-formatting}
1501 md - markdown {use markdown-formatting}
1502 default {use text-formatting}
1505 title "[autosetup_version
] -- Command Reference
"
1507 section {Introduction}
1510 See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
1514 'autosetup' provides a number of built-in commands which
1515 are documented below. These may be used from 'auto.def' to test
1516 for features, define variables, create files from templates and
1517 other similar actions.
1520 automf_command_reference
1525 proc autosetup_output_block {type lines} {
1526 if {[llength $lines]} {
1541 foreach line $lines {
1550 # Generate a command reference from inline documentation
1551 proc automf_command_reference {} {
1552 lappend files $::autosetup(prog)
1553 lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
1555 # We want to process all non-module files before module files
1556 # and then modules in alphabetical order.
1557 # So examine all files and extract docs into doc($modulename) and doc(_core_)
1559 # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
1560 # and $data is a string for section, subsection or a list of text lines for other types.
1562 # XXX: Should commands be in alphabetical order too? Currently they are in file order.
1565 lappend doc(_core_) [list section "Core Commands
"]
1567 foreach file $files {
1568 set modulename [file rootname [file tail $file]]
1574 # Find embedded module names
1575 if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
1579 # Find lines starting with "# @*" and continuing through the remaining comment lines
1580 if {![regexp
{^
# @(.*)} $line -> cmd]} {
1584 # Synopsis or command?
1585 if {$cmd eq
"synopsis:"} {
1586 set current
$modulename
1587 lappend doc
($current) [list section
"Module: $modulename"]
1589 lappend doc
($current) [list subsection
$cmd]
1595 # Now the description
1599 if {![regexp
{^
#(#)? ?(.*)} $line -> hash cmd]} {
1604 } elseif
{[regexp
{^
- (.
*)} $cmd -> cmd
]} {
1610 #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
1612 if {$t ne
$type ||
$cmd eq
""} {
1613 # Finish the current block
1614 lappend doc
($current) [list
$type $lines]
1623 lappend doc
($current) [list
$type $lines]
1628 # Now format and output the results
1630 # _core_ will sort first
1631 foreach module
[lsort
[array names doc
]] {
1632 foreach item
$doc($module) {
1633 autosetup_output_block
{*}$item
1639 # ----- @module init.tcl -----
1641 set modsource
(init.tcl
) {
1642 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1643 # All rights reserved
1645 # Module to help create auto.def and configure
1647 proc autosetup_init
{type} {
1649 if {$type in {?
help}} {
1651 } elseif
{![dict exists $
::autosetup
(inittypes
) $type]} {
1652 puts
"Unknown type, --init=$type"
1656 puts
"Use one of the following types (e.g. --init=make)\n"
1657 foreach
type [lsort
[dict keys $
::autosetup
(inittypes
)]] {
1658 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
1659 # XXX: Use the options-show code to wrap the description
1660 puts
[format
"%-10s %s" $type $desc]
1664 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
script
1666 puts
"Initialising $type: $desc\n"
1668 # All initialisations happens in the top level srcdir
1669 cd $
::autosetup
(srcdir
)
1674 proc autosetup_add_init_type
{type desc
script} {
1675 dict
set ::autosetup
(inittypes
) $type [list
$desc $script]
1678 # This is for in creating build-system init scripts
1680 # If the file doesn't exist, create it containing $contents
1681 # If the file does exist, only overwrite if --force is specified.
1683 proc autosetup_check_create
{filename contents
} {
1684 if {[file exists
$filename]} {
1685 if {!$
::autosetup
(force
)} {
1686 puts
"I see $filename already exists."
1689 puts
"I will overwrite the existing $filename because you used --force."
1692 puts
"I don't see $filename, so I will create it."
1694 writefile
$filename $contents
1698 # ----- @module install.tcl -----
1700 set modsource
(install.tcl
) {
1701 # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
1702 # All rights reserved
1704 # Module which can install autosetup
1706 # autosetup(installed)=1 means that autosetup is not running from source
1707 # autosetup(sysinstall)=1 means that autosetup is running from a sysinstall version
1708 # shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
1710 proc autosetup_install
{dir
{shared
0}} {
1713 if {$autosetup(installed
) ||
$autosetup(sysinstall
)} {
1714 user-error
"Can only --sysinstall from development sources"
1716 } elseif
{$autosetup(installed
) && !$autosetup(sysinstall
)} {
1717 user-error
"Can't --install from project install"
1720 if {$autosetup(sysinstall
)} {
1721 # This is the sysinstall version, so install just uses references
1724 puts
"[autosetup_version] creating configure to use system-installed autosetup"
1725 autosetup_create_configure
1
1726 puts
"Creating autosetup/README.autosetup"
1727 file mkdir autosetup
1728 autosetup_install_readme autosetup
/README.autosetup
1
1734 set target
$dir/bin
/autosetup
1735 set installedas
$target
1738 set installedas autosetup
1740 set installedas
$dir/autosetup
1743 file mkdir autosetup
1744 set target autosetup
/autosetup
1746 set targetdir
[file dirname $target]
1747 file mkdir
$targetdir
1749 set f
[open
$target w
]
1751 set publicmodules
{}
1753 # First the main script, but only up until "CUT HERE"
1754 set in [open
$autosetup(dir
)/autosetup
]
1755 while {[gets
$in buf
] >= 0} {
1756 if {$buf ne
"##-- CUT HERE --##"} {
1761 # Insert the static modules here
1762 # i.e. those which don't contain @synopsis:
1763 # All modules are inserted if $shared is set
1764 puts
$f "set autosetup(installed) 1"
1765 puts
$f "set autosetup(sysinstall) $shared"
1766 foreach
file [lsort
[glob
$autosetup(libdir
)/*.
{tcl
,auto
}]] {
1767 set modname
[file tail $file]
1768 set ext
[file ext
$modname]
1769 set buf
[readfile
$file]
1771 if {$ext eq
".auto" ||
[string match
"*\n# @synopsis:*" $buf]} {
1772 lappend publicmodules
$file
1776 dputs
"install: importing lib/[file tail $file]"
1777 puts
$f "# ----- @module $modname -----"
1778 puts
$f "\nset modsource($modname) \{"
1783 foreach
{srcname destname
} [list
$autosetup(libdir
)/README.autosetup-lib README.autosetup \
1784 $autosetup(srcdir
)/LICENSE LICENSE
] {
1785 dputs
"install: importing $srcname as $destname"
1786 puts
$f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
1792 catch
{exec chmod 755 $target}
1794 set installfiles
{autosetup-config.guess autosetup-config.sub autosetup-test-tclsh
}
1798 autosetup_install_readme
$targetdir/README.autosetup
0
1800 # Install public modules
1801 foreach
file $publicmodules {
1802 set tail [file tail $file]
1803 autosetup_install_file
$file $targetdir/$tail
1805 lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
1806 lappend removefiles config.guess config.sub test-tclsh find-tclsh
1808 lappend installfiles
{sys-find-tclsh autosetup-find-tclsh
}
1811 # Install support files
1812 foreach fileinfo
$installfiles {
1813 if {[llength
$fileinfo] == 2} {
1814 lassign
$fileinfo source dest
1816 lassign
$fileinfo source
1819 autosetup_install_file
$autosetup(dir
)/$source $targetdir/$dest
1822 # Remove obsolete files
1823 foreach
file $removefiles {
1824 if {[file exists
$targetdir/$file]} {
1825 file delete
$targetdir/$file
1829 user-error
"Failed to install autosetup: $error"
1836 puts
"Installed $type [autosetup_version] to $installedas"
1839 # Now create 'configure' if necessary
1840 autosetup_create_configure
0
1844 proc autosetup_create_configure
{shared
} {
1845 if {[file exists configure
]} {
1846 if {!$
::autosetup
(force
)} {
1847 # Could this be an autosetup configure?
1848 if {![string match
"*\nWRAPPER=*" [readfile configure
]]} {
1849 puts
"I see configure, but not created by autosetup, so I won't overwrite it."
1850 puts
"Remove it or use --force to overwrite."
1854 puts
"I will overwrite the existing configure because you used --force."
1857 puts
"I don't see configure, so I will create it."
1860 writefile configure \
1862 WRAPPER
="$0"; export WRAPPER
; "autosetup" "$@"
1865 writefile configure \
1867 dir
="`dirname "$0"`/autosetup"
1868 WRAPPER
="$0"; export WRAPPER
; exec "`"$dir/autosetup-find-tclsh
"`" "$dir/autosetup" "$@"
1871 catch
{exec chmod 755 configure
}
1874 # Append the contents of $file to filehandle $f
1875 proc autosetup_install_append
{f
file} {
1876 dputs
"install: include $file"
1882 proc autosetup_install_file
{source target
} {
1883 dputs
"install: $source => $target"
1884 if {![file exists
$source]} {
1885 error
"Missing installation file '$source'"
1887 writefile
$target [readfile
$source]\n
1888 # If possible, copy the file mode
1889 file stat
$source stat
1890 set mode
[format
%o
[expr {$stat(mode
) & 0x1ff}]]
1891 catch
{exec chmod $mode $target}
1894 proc autosetup_install_readme
{target sysinstall
} {
1895 set readme
"README.autosetup created by [autosetup_version]\n\n"
1898 {This is the autosetup directory
for a system
install of autosetup.
1899 Loadable modules can be added here.
1903 {This is the autosetup directory
for a
local install of autosetup.
1904 It contains autosetup
, support files and loadable modules.
1909 *.tcl files
in this directory are optional modules
which
1910 can be loaded with the
'use' directive.
1912 *.auto files
in this directory are auto-loaded.
1914 For
more information
, see http
://msteveb.github.com
/autosetup
/
1916 dputs
"install: autosetup/README.autosetup"
1917 writefile
$target $readme
1921 # ----- @module markdown-formatting.tcl -----
1923 set modsource
(markdown-formatting.tcl
) {
1924 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1925 # All rights reserved
1927 # Module which provides text formatting
1928 # markdown format (kramdown syntax)
1933 regsub
-all "\[ \t\n\]+" [string trim
$text] " " text
1934 regsub
-all {([^a-zA-Z
])'([^']*)'} $text {\1**`\2`**} text
1935 regsub -all {^'([^
']*)'} $text {**`\1`**} text
1936 regsub
-all {(http
[^
\t\n]*)} $text {[\
1](\
1)} text
1940 underline
[para
$text] =
1947 proc codelines
{lines
} {
1949 foreach line
$lines {
1957 foreach line
[parse_code_block
$text] {
1966 proc underline
{text char
} {
1967 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
1969 puts
$indent[string repeat
$char [string length
$words]]
1971 proc section
{text
} {
1972 underline
"[para $text]" -
1975 proc subsection
{text
} {
1979 proc bullet
{text
} {
1980 puts
"* [para $text]"
1982 proc defn
{first args
} {
1984 set defn
[string trim
[join $args \n]]
1987 puts
-nonewline ": "
1988 regsub
-all "\n\n" $defn "\n: " defn
1994 # ----- @module misc.tcl -----
1996 set modsource
(misc.tcl
) {
1997 # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
1998 # All rights reserved
2000 # Module containing misc procs useful to modules
2001 # Largely for platform compatibility
2003 set autosetup
(istcl
) [info exists
::tcl_library
]
2004 set autosetup
(iswin
) [string equal windows
$tcl_platform(platform
)]
2006 if {$autosetup(iswin
)} {
2007 # mingw/windows separates $PATH with semicolons
2008 # and doesn't have an executable bit
2009 proc split-path
{} {
2010 split [getenv PATH .
] {;}
2012 proc file-isexec
{exec} {
2013 # Basic test for windows. We ignore .bat
2014 if {[file isfile
$exec] ||
[file isfile
$exec.exe
]} {
2020 # unix separates $PATH with colons and has and executable bit
2021 proc split-path
{} {
2022 split [getenv PATH .
] :
2024 proc file-isexec
{exec} {
2025 file executable
$exec
2029 # Assume that exec can return stdout and stderr
2030 proc exec-with-stderr
{args
} {
2034 if {$autosetup(istcl
)} {
2035 # Tcl doesn't have the env command
2036 proc getenv
{name args
} {
2037 if {[info exists
::env
($name)]} {
2038 return $
::env
($name)
2040 if {[llength
$args]} {
2041 return [lindex
$args 0]
2043 return -code error
"environment variable \"$name\" does not exist"
2045 proc isatty?
{channel
} {
2046 dict exists
[fconfigure
$channel] -xchar
2049 if {$autosetup(iswin
)} {
2050 # On Windows, backslash convert all environment variables
2051 # (Assume that Tcl does this for us)
2052 proc getenv
{name args
} {
2053 string map
{\\ /} [env
$name {*}$args]
2056 # Jim on unix is simple
2059 proc isatty?
{channel
} {
2062 # isatty is a recent addition to Jim Tcl
2063 set tty
[$channel isatty
]
2069 # In case 'file normalize' doesn't exist
2071 proc file-normalize
{path
} {
2072 if {[catch
{file normalize
$path} result
]} {
2077 if {[file isdir
$path]} {
2081 cd [file dirname $path]
2082 set result
[file join [pwd] [file tail $path]]
2089 # If everything is working properly, the only errors which occur
2090 # should be generated in user code (e.g. auto.def).
2091 # By default, we only want to show the error location in user code.
2092 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
2094 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
2096 proc error-location
{msg
} {
2097 if {$
::autosetup
(debug
)} {
2098 return -code error
$msg
2100 # Search back through the stack trace for the first error in a .def file
2101 for {set i
1} {$i < [info level
]} {incr i
} {
2102 if {$
::autosetup
(istcl
)} {
2103 array
set info
[info frame
-$i]
2105 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
2107 if {[string match
*.def
$info(file)]} {
2108 return "[relative-path $info(file)]:$info(line): Error: $msg"
2110 #puts "Skipping $info(file):$info(line)"
2115 # If everything is working properly, the only errors which occur
2116 # should be generated in user code (e.g. auto.def).
2117 # By default, we only want to show the error location in user code.
2118 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
2120 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
2122 proc error-stacktrace
{msg
} {
2123 if {$
::autosetup
(debug
)} {
2124 return -code error
$msg
2126 # Search back through the stack trace for the first error in a .def file
2127 for {set i
1} {$i < [info level
]} {incr i
} {
2128 if {$
::autosetup
(istcl
)} {
2129 array
set info
[info frame
-$i]
2131 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
2133 if {[string match
*.def
$info(file)]} {
2134 return "[relative-path $info(file)]:$info(line): Error: $msg"
2136 #puts "Skipping $info(file):$info(line)"
2141 # Given the return from [catch {...} msg opts], returns an appropriate
2142 # error message. A nice one for Jim and a less-nice one for Tcl.
2143 # If 'fulltrace' is set, a full stack trace is provided.
2144 # Otherwise a simple message is provided.
2146 # This is designed for developer errors, e.g. in module code or auto.def code
2149 proc error-dump
{msg opts fulltrace
} {
2150 if {$
::autosetup
(istcl
)} {
2152 return "Error: [dict get $opts -errorinfo]"
2154 return "Error: $msg"
2157 lassign
$opts(-errorinfo) p f l
2159 set result
"$f:$l: Error: "
2161 append result
"$msg\n"
2163 append result
[stackdump
$opts(-errorinfo)]
2166 # Remove the trailing newline
2172 # ----- @module text-formatting.tcl -----
2174 set modsource
(text-formatting.tcl
) {
2175 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2176 # All rights reserved
2178 # Module which provides text formatting
2182 proc wordwrap
{text length
{firstprefix
""} {nextprefix
""}} {
2184 set space
$firstprefix
2186 foreach word
[split $text] {
2187 set word
[string trim
$word]
2191 if {[info exists partial
]} {
2192 append partial
" " $word
2193 if {[string first
$quote $word] < 0} {
2194 # Haven't found end of quoted word
2197 # Finished quoted word
2202 set quote
[string index
$word 0]
2203 if {$quote in {' *}} {
2204 if {[string first $quote $word 1] < 0} {
2205 # Haven't found end of quoted word
2207 set first
[string index
$word 0]
2208 # Start of quoted word
2215 if {$len && [string length
$space$word] + $len >= $length} {
2218 set space
$nextprefix
2220 incr len
[string length
$space$word]
2222 # Use man-page conventions for highlighting 'quoted' and *quoted*
2224 # Use x^Hx for *bold* and _^Hx for 'underline'.
2226 # less and more will both understand this.
2227 # Pipe through 'col -b' to remove them.
2228 if {[regexp
{^
'(.*)'(.
*)} $word -> quoted after
]} {
2229 set quoted
[string map
{~
" "} $quoted]
2230 regsub
-all .
$quoted "&\b&" quoted
2231 set word
$quoted$after
2232 } elseif
{[regexp
{^
[*](.
*)[*](.
*)} $word -> quoted after
]} {
2233 set quoted
[string map
{~
" "} $quoted]
2234 regsub
-all .
$quoted "_\b&" quoted
2235 set word
$quoted$after
2237 puts
-nonewline $space$word
2240 if {[info exists partial
]} {
2241 # Missing end of quote
2242 puts
-nonewline $space$partial
2249 underline
[string trim
$text] =
2256 proc codelines
{lines
} {
2257 foreach line
$lines {
2265 proc underline
{text char
} {
2266 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
2268 puts
$indent[string repeat
$char [string length
$words]]
2270 proc section
{text
} {
2271 underline
"[string trim $text]" -
2274 proc subsection
{text
} {
2278 proc bullet
{text
} {
2279 wordwrap
$text 76 " * " " "
2281 proc indent
{text
} {
2282 wordwrap
$text 76 " " " "
2284 proc defn
{first args
} {
2286 underline
" $first" ~
2296 # ----- @module util.tcl -----
2298 set modsource
(util.tcl
) {
2299 # Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
2300 # All rights reserved
2302 # Module which contains miscellaneous utility functions
2304 # @compare-versions version1 version2
2306 # Versions are of the form 'a.b.c' (may be any number of numeric components)
2308 # Compares the two versions and returns:
2313 # If one version has fewer components than the other, 0 is substituted to the right. e.g.
2318 proc compare-versions
{v1 v2
} {
2319 foreach c1
[split $v1 .
] c2
[split $v2 .
] {
2338 # Takes a list and returns a new list with '$suf' appended
2341 ## suffix .c {a b c} => {a.c b.c c.c}
2343 proc suffix
{suf list
} {
2346 lappend result
$p$suf
2353 # Takes a list and returns a new list with '$pre' prepended
2356 ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
2358 proc prefix
{pre list
} {
2361 lappend result
$pre$p
2368 # Removes the last entry from the given list and returns it.
2369 proc lpop
{listname
} {
2370 upvar
$listname list
2371 set val
[lindex
$list end
]
2372 set list
[lrange
$list 0 end-1
]
2377 # ----- @module wiki-formatting.tcl -----
2379 set modsource
(wiki-formatting.tcl
) {
2380 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2381 # All rights reserved
2383 # Module which provides text formatting
2384 # wiki.tcl.tk format output
2388 proc joinlines
{text
} {
2390 foreach l
[split [string trim
$text] \n] {
2391 lappend lines
[string trim
$l]
2396 puts
[joinlines
$text]
2400 puts
"*** [joinlines $text] ***"
2403 proc codelines
{lines
} {
2405 foreach line
$lines {
2412 foreach line
[parse_code_block
$text] {
2419 proc section
{text
} {
2423 proc subsection
{text
} {
2427 proc bullet
{text
} {
2428 puts
" * [joinlines $text]"
2430 proc indent
{text
} {
2431 puts
" : [joinlines $text]"
2433 proc defn
{first args
} {
2445 ##################################################################
2449 if {$autosetup(debug
)} {
2452 if {[catch
{main
$argv} msg opts
] == 1} {
2454 autosetup-full-error
[error-dump
$msg $opts $autosetup(debug
)]
2455 if {!$autosetup(debug
)} {
2456 puts stderr
"Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"