2 # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
6 dir
=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
8 set autosetup
(version
) 0.6.8
10 # Can be set to 1 to debug early-init problems
11 set autosetup
(debug
) [expr {"--debug" in $argv}]
13 ##################################################################
15 # Main flow of control, option handling
18 global autosetup define
20 # There are 3 potential directories involved:
21 # 1. The directory containing autosetup (this script)
22 # 2. The directory containing auto.def
23 # 3. The current directory
25 # From this we need to determine:
26 # a. The path to this script (and related support files)
27 # b. The path to auto.def
28 # c. The build directory, where output files are created
30 # This is also complicated by the fact that autosetup may
31 # have been run via the configure wrapper ([getenv WRAPPER] is set)
34 # a. This script is $::argv0
35 # => dir, prog, exe, libdir
36 # b. auto.def is in the directory containing the configure wrapper,
37 # otherwise it is in the current directory.
39 # c. The build directory is the current directory
42 # 'misc' is needed before we can do anything, so set a temporary libdir
43 # in case this is the development version
44 set autosetup
(libdir
) [file dirname $
::argv0
]/lib
48 set autosetup
(dir
) [realdir
[file dirname [realpath $
::argv0
]]]
49 set autosetup
(prog
) [file join $autosetup(dir
) [file tail $
::argv0
]]
50 set autosetup
(exe
) [getenv WRAPPER
$autosetup(prog
)]
51 if {$autosetup(installed
)} {
52 set autosetup
(libdir
) $autosetup(dir
)
54 set autosetup
(libdir
) [file join $autosetup(dir
) lib
]
56 autosetup_add_dep
$autosetup(prog
)
59 if {[getenv WRAPPER
""] eq
""} {
61 set autosetup
(srcdir
) [pwd]
63 # Invoked via the configure wrapper
64 set autosetup
(srcdir
) [file-normalize
[file dirname $autosetup(exe
)]]
66 set autosetup
(autodef
) [relative-path
$autosetup(srcdir
)/auto.def
]
69 set autosetup
(builddir
) [pwd]
71 set autosetup
(argv
) $argv
72 set autosetup
(cmdline
) {}
73 # options is a list of known options
74 set autosetup
(options
) {}
75 # optset is a dictionary of option values set by the user based on getopt
76 set autosetup
(optset
) {}
77 # optdefault is a dictionary of default values
78 set autosetup
(optdefault
) {}
79 # options-defaults is a dictionary of overrides for default values for options
80 set autosetup
(options-defaults
) {}
81 set autosetup
(optionhelp
) {}
82 set autosetup
(showhelp
) 0
87 # At the is point we don't know what is a valid option
88 # We simply parse anything that looks like an option
89 set autosetup
(getopt
) [getopt argv
]
93 help:=local => "display help and options. Optionally specify a module name, such as --help=system"
94 licence license
=> "display the autosetup license"
95 version
=> "display the version of autosetup"
96 ref
:=text manual
:=text
97 reference
:=text
=> "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
98 debug
=> "display debugging output as autosetup runs"
99 install:=.
=> "install autosetup to the current or given directory"
101 if {$autosetup(installed
)} {
102 # hidden options so we can produce a nice error
108 sysinstall
:path
=> "install standalone autosetup to the given directory (e.g.: /usr/local)"
112 force init
:=help => "create initial auto.def, etc. Use --init=help for known types"
113 # Undocumented options
121 if {[opt-bool version
]} {
122 puts
$autosetup(version
)
126 # autosetup --conf=alternate-auto.def
127 if {[opt-str conf o
]} {
128 set autosetup
(autodef
) $o
131 # Debugging output (set this early)
132 incr autosetup
(debug
) [opt-bool debug
]
133 incr autosetup
(force
) [opt-bool force
]
134 incr autosetup
(msg-quiet
) [opt-bool quiet
]
135 incr autosetup
(msg-timing
) [opt-bool timing
]
137 # If the local module exists, source it now to allow for
138 # project-local customisations
139 if {[file exists
$autosetup(libdir
)/local.tcl
]} {
143 # Now any auto-load modules
144 autosetup_load_auto_modules
146 if {[opt-str
help o
]} {
147 incr autosetup
(showhelp
)
152 if {[opt-bool licence license
]} {
154 autosetup_show_license
158 if {[opt-str
{manual ref reference
} o
]} {
160 autosetup_reference
$o
163 # Allow combining --install and --init
165 if {[opt-str
install o
]} {
171 if {[opt-str init o
]} {
180 if {[opt-str sysinstall o
]} {
182 autosetup_install
$o 1
186 if {![file exists
$autosetup(autodef
)]} {
187 # Check for invalid option first
189 user-error
"No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
192 # Parse extra arguments into autosetup(cmdline)
194 if {[regexp
{([^
=]*)=(.
*)} $arg -> n v
]} {
195 dict
set autosetup
(cmdline
) $n $v
198 user-error
"Unexpected parameter: $arg"
202 autosetup_add_dep
$autosetup(autodef
)
204 define CONFIGURE_OPTS
""
205 foreach arg
$autosetup(argv
) {
206 define-append CONFIGURE_OPTS
[quote-if-needed
$arg]
208 define AUTOREMAKE
[file-normalize
$autosetup(exe
)]
209 define-append AUTOREMAKE
[get-define CONFIGURE_OPTS
]
212 # Log how we were invoked
213 configlog
"Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
215 # Note that auto.def is *not* loaded in the global scope
216 source $autosetup(autodef
)
218 # Could warn here if options {} was not specified
222 if {$autosetup(debug
)} {
223 msg-result
"Writing all defines to config.log"
224 configlog
"================ defines ======================"
225 foreach n
[lsort
[array names define
]] {
226 configlog
"define $n $define($n)"
233 # @opt-bool ?-nodefault? option ...
235 # Check each of the named, boolean options and if any have been explicitly enabled
236 # or disabled by the user, return 1 or 0 accordingly.
238 # If the option was specified more than once, the last value wins.
239 # e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
241 # If no value was specified by the user, returns the default value for the
242 # first option. If '-nodefault' is given, this behaviour changes and
243 # -1 is returned instead.
245 proc opt-bool
{args
} {
247 if {[lindex
$args 0] eq
"-nodefault"} {
249 set args
[lrange
$args 1 end
]
251 option-check-names
{*}$args
254 if {[dict exists $
::autosetup
(optset
) $opt]} {
255 return [dict get $
::autosetup
(optset
) $opt]
262 # Default value is the default for the first option
263 return [dict get $
::autosetup
(optdefault
) [lindex
$args 0]]
266 # @opt-val optionlist ?default=""?
268 # Returns a list containing all the values given for the non-boolean options in '$optionlist'.
269 # There will be one entry in the list for each option given by the user, including if the
270 # same option was used multiple times.
272 # If no options were set, '$default' is returned (exactly, not as a list).
274 # Note: For most use cases, 'opt-str' should be preferred.
276 proc opt-val
{names
{default
""}} {
277 option-check-names
{*}$names
280 if {[dict exists $
::autosetup
(optset
) $opt]} {
281 lappend result
{*}[dict get $
::autosetup
(optset
) $opt]
284 if {[info exists result
]} {
290 # @opt-str optionlist varname ?default?
292 # Sets '$varname' in the callers scope to the value for one of the given options.
294 # For the list of options given in '$optionlist', if any value is set for any option,
295 # the option value is taken to be the *last* value of the last option (in the order given).
297 # If no option was given, and a default was specified with 'options-defaults',
298 # that value is used.
300 # If no 'options-defaults' value was given and '$default' was given, it is used.
302 # If none of the above provided a value, no value is set.
304 # The return value depends on whether '$default' was specified.
305 # If it was, the option value is returned.
306 # If it was not, 1 is returns if a value was set, or 0 if not.
308 # Typical usage is as follows:
310 ## if {[opt-str {myopt altname} o]} {
311 ## do something with $o
315 ## define myname [opt-str {myopt altname} o "/usr/local"]
317 proc opt-str
{names varname args
} {
320 option-check-names
{*}$names
323 if {[llength
$args]} {
324 # A default was given, so always return the string value of the option
325 set default
[lindex
$args 0]
328 # No default, so return 0 or 1 to indicate if a value was found
333 if {[dict exists $
::autosetup
(optset
) $opt]} {
334 set result
[lindex
[dict get $
::autosetup
(optset
) $opt] end
]
338 if {![info exists result
]} {
339 # No user-specified value. Has options-defaults been set?
341 if {[dict exists $
::autosetup
(options-defaults
) $opt]} {
342 set result
[dict get
$autosetup(options-defaults
) $opt]
347 if {[info exists result
]} {
363 proc option-check-names
{args
} {
365 if {$o ni $
::autosetup
(options
)} {
366 autosetup-error
"Request for undeclared option --$o"
371 # Parse the option definition in $opts and update
372 # ::autosetup(setoptions) and ::autosetup(optionhelp) appropriately
374 proc options-add
{opts
{header
""}} {
377 # First weed out comment lines
379 foreach line
[split $opts \n] {
380 if {![string match
"#*" [string trimleft
$line]]} {
381 append realopts
$line \n
386 for {set i
0} {$i < [llength
$opts]} {incr i
} {
387 set opt
[lindex
$opts $i]
388 if {[string match
=* $opt]} {
389 # This is a special heading
390 lappend autosetup
(optionhelp
) $opt ""
394 unset -nocomplain defaultvalue equal value
396 #puts "i=$i, opt=$opt"
397 regexp
{^
([^
:=]*)(:)?
(=)?
(.
*)$
} $opt -> name colon equal value
398 if {$name in $autosetup(options
)} {
399 autosetup-error
"Option $name already specified"
402 #puts "$opt => $name $colon $equal $value"
404 # Find the corresponding value in the user options
405 # and set the default if necessary
406 if {[string match
"-*" $opt]} {
407 # This is a documentation-only option, like "-C <dir>"
409 } elseif
{$colon eq
""} {
411 lappend autosetup
(options
) $name
414 if {[dict exists
$autosetup(options-defaults
) $name]} {
415 # A default was specified with options-defaults, so use it
416 set value
[dict get
$autosetup(options-defaults
) $name]
420 set opthelp
"--disable-$name"
422 set opthelp
"--$name"
429 set defaultvalue
$value
430 dict
set autosetup
(optdefault
) $name $defaultvalue
432 if {[dict exists
$autosetup(getopt
) $name]} {
433 # The option was specified by the user. Look at the last value.
434 lassign
[lindex
[dict get
$autosetup(getopt
) $name] end
] type setvalue
435 if {$type eq
"str"} {
436 # Can we convert the value to a boolean?
437 if {$setvalue in {1 enabled
yes}} {
439 } elseif
{$setvalue in {0 disabled no
}} {
442 user-error
"Boolean option $name given as --$name=$setvalue"
445 dict
set autosetup
(optset
) $name $setvalue
446 #puts "Found boolean option --$name=$setvalue"
450 lappend autosetup
(options
) $name
453 # Was ":name=default" given?
454 # If so, set $value to the display name and $defaultvalue to the default
455 # (This is the preferred way to set a default value for a string option)
456 if {[regexp
{^
([^
=]+)=(.
*)$
} $value -> value defaultvalue
]} {
457 dict
set autosetup
(optdefault
) $name $defaultvalue
461 # Maybe override the default value
462 if {[dict exists
$autosetup(options-defaults
) $name]} {
463 # A default was specified with options-defaults, so use it
464 set defaultvalue
[dict get
$autosetup(options-defaults
) $name]
465 dict
set autosetup
(optdefault
) $name $defaultvalue
466 } elseif
{![info exists defaultvalue
]} {
467 # For backward compatiblity, if ":name" was given, use name as both
468 # the display text and the default value, but only if the user
469 # specified the option without the value
470 set defaultvalue
$value
474 # String option with optional value
475 set opthelp
"--$name?=$value?"
477 # String option with required value
478 set opthelp
"--$name=$value"
481 # Get the values specified by the user
482 if {[dict exists
$autosetup(getopt
) $name]} {
485 foreach pair
[dict get
$autosetup(getopt
) $name] {
486 lassign
$pair type setvalue
487 if {$type eq
"bool" && $setvalue} {
489 user-error
"Option --$name requires a value"
491 # If given as a boolean, use the default value
492 set setvalue
$defaultvalue
494 lappend listvalue
$setvalue
497 #puts "Found string option --$name=$listvalue"
498 dict
set autosetup
(optset
) $name $listvalue
502 # Now create the help for this option if appropriate
503 if {[lindex
$opts $i+1] eq
"=>"} {
504 set desc
[lindex
$opts $i+2]
505 if {[info exists defaultvalue
]} {
506 set desc
[string map
[list @default@
$defaultvalue] $desc]
508 #string match \n* $desc
510 lappend autosetup
(optionhelp
) $header ""
513 # A multi-line description
514 lappend autosetup
(optionhelp
) $opthelp $desc
520 # @module-options optionlist
522 # Like 'options', but used within a module.
523 proc module-options
{opts
} {
525 if {$
::autosetup
(showhelp
) > 1 && [llength
$opts]} {
526 set header
"Module Options:"
528 options-add
$opts $header
530 if {$
::autosetup
(showhelp
)} {
531 # Ensure that the module isn't executed on --help
532 # We are running under eval or source, so use break
533 # to prevent further execution
534 #return -code break -level 2
540 expr {$a > $b ?
$a : $b}
543 proc options-wrap-desc
{text length firstprefix nextprefix initial
} {
545 set space
$firstprefix
546 foreach word
[split $text] {
547 set word
[string trim
$word]
551 if {$len && [string length
$space$word] + $len >= $length} {
554 set space
$nextprefix
556 incr len
[string length
$space$word]
557 puts
-nonewline $space$word
565 proc options-show
{} {
566 # Determine the max option width
568 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
569 if {[string match
=* $opt] ||
[string match
\n* $desc]} {
572 set max
[max
$max [string length
$opt]]
574 set indent
[string repeat
" " [expr $max+4]]
575 set cols
[getenv COLUMNS
80]
577 lassign
[exec stty size
] rows cols
581 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
582 if {[string match
=* $opt]} {
583 puts
[string range
$opt 1 end
]
586 puts
-nonewline " [format %-${max}s $opt]"
587 if {[string match
\n* $desc]} {
590 options-wrap-desc
[string trim
$desc] $cols " " $indent [expr $max + 2]
595 # @options optionspec
597 # Specifies configuration-time options which may be selected by the user
598 # and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
599 # of options specifications separated by newlines, as follows:
601 # A boolean option is of the form:
603 ## name[=0|1] => "Description of this boolean option"
605 # The default is 'name=0', meaning that the option is disabled by default.
606 # If 'name=1' is used to make the option enabled by default, the description should reflect
607 # that with text like "Disable support for ...".
609 # An argument option (one which takes a parameter) is of the form:
611 ## name:[=]value => "Description of this option"
613 # If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
614 # If the 'name:=value' form is used, the value is optional and the given value is used as the default
615 # if it is not provided.
617 # The description may contain '@default@', in which case it will be replaced with the default
618 # value for the option (taking into account defaults specified with 'options-defaults'.
620 # Undocumented options are also supported by omitting the '=> description'.
621 # These options are not displayed with '--help' and can be useful for internal options or as aliases.
623 # For example, '--disable-lfs' is an alias for '--disable=largefile':
625 ## lfs=1 largefile=1 => "Disable large file support"
627 proc options
{optlist
} {
628 # Allow options as a list or args
629 options-add
$optlist "Local Options:"
631 if {$
::autosetup
(showhelp
)} {
636 # Check for invalid options
637 if {[opt-bool option-checking
]} {
638 foreach o
[dict keys $
::autosetup
(getopt
)] {
639 if {$o ni $
::autosetup
(options
)} {
640 user-error
"Unknown option --$o"
646 # @options-defaults dictionary
648 # Specifies a dictionary of options and a new default value for each of those options.
649 # Use before any 'use' statements in 'auto.def' to change the defaults for
650 # subsequently included modules.
651 proc options-defaults
{dict
} {
652 foreach
{n v
} $dict {
653 dict
set ::autosetup
(options-defaults
) $n $v
657 proc config_guess
{} {
658 if {[file-isexec $
::autosetup
(dir
)/autosetup-config.guess
]} {
659 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/autosetup-config.guess
} alias]} {
664 configlog
"No autosetup-config.guess, so using uname"
665 string tolower
[exec uname
-p]-unknown-[exec uname
-s][exec uname
-r]
669 proc config_sub
{alias} {
670 if {[file-isexec $
::autosetup
(dir
)/autosetup-config.sub
]} {
671 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/autosetup-config.sub
$alias} alias]} {
678 # @define name ?value=1?
680 # Defines the named variable to the given value.
681 # These (name, value) pairs represent the results of the configuration check
682 # and are available to be subsequently checked, modified and substituted.
684 proc define
{name
{value
1}} {
685 set ::define
($name) $value
686 #dputs "$name <= $value"
691 # Undefine the named variable.
693 proc undefine
{name
} {
694 unset -nocomplain ::define
($name)
695 #dputs "$name <= <undef>"
698 # @define-append name value ...
700 # Appends the given value(s) to the given "defined" variable.
701 # If the variable is not defined or empty, it is set to '$value'.
702 # Otherwise the value is appended, separated by a space.
703 # Any extra values are similarly appended.
704 # If any value is already contained in the variable (as a substring) it is omitted.
706 proc define-append
{name args
} {
707 if {[get-define
$name ""] ne
""} {
711 foreach str
[split $
::define
($name) " "] {
717 append
::define
($name) " " $arg
721 set ::define
($name) [join $args]
723 #dputs "$name += [join $args] => $::define($name)"
726 # @get-define name ?default=0?
728 # Returns the current value of the "defined" variable, or '$default'
731 proc get-define
{name
{default
0}} {
732 if {[info exists
::define
($name)]} {
733 #dputs "$name => $::define($name)"
734 return $
::define
($name)
736 #dputs "$name => $default"
742 # Returns 1 if the given variable is defined.
744 proc is-defined
{name
} {
745 info exists
::define
($name)
750 # Returns a dictionary (name, value list) of all defined variables.
752 # This is suitable for use with 'dict', 'array set' or 'foreach'
753 # and allows for arbitrary processing of the defined variables.
755 proc all-defines
{} {
760 # @get-env name default
762 # If '$name' was specified on the command line, return it.
763 # Otherwise if '$name' was set in the environment, return it.
764 # Otherwise return '$default'.
766 proc get-env
{name default
} {
767 if {[dict exists $
::autosetup
(cmdline
) $name]} {
768 return [dict get $
::autosetup
(cmdline
) $name]
770 getenv
$name $default
775 # Returns 1 if '$name' was specified on the command line or in the environment.
776 # Note that an empty environment variable is not considered to be set.
778 proc env-is-set
{name
} {
779 if {[dict exists $
::autosetup
(cmdline
) $name]} {
782 if {[getenv
$name ""] ne
""} {
788 # @readfile filename ?default=""?
790 # Return the contents of the file, without the trailing newline.
791 # If the file doesn't exist or can't be read, returns '$default'.
793 proc readfile
{filename
{default_value
""}} {
794 set result
$default_value
796 set f
[open
$filename]
797 set result
[read -nonewline $f]
803 # @writefile filename value
805 # Creates the given file containing '$value'.
806 # Does not add an extra newline.
808 proc writefile
{filename value
} {
809 set f
[open
$filename w
]
810 puts
-nonewline $f $value
814 proc quote-if-needed
{str
} {
815 if {[string match
{*[\" ]*} $str]} {
816 return \"[string map
[list
\" \\" \\ \\\\] $str]\"
821 proc quote-argv {argv} {
824 lappend args [quote-if-needed $arg]
829 # @list-non-empty list
831 # Returns a copy of the given list with empty elements removed
832 proc list-non-empty {list} {
842 # @find-executable-path name
844 # Searches the path for an executable with the given name.
845 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
846 # in which case the parameters are ignored.
847 # The full path to the executable if found, or "" if not found.
848 # Returns 1 if found, or 0 if not.
850 proc find-executable-path {name} {
851 # Ignore any parameters
852 set name [lindex $name 0]
853 # The empty string is never a valid executable
855 foreach p [split-path] {
856 dputs "Looking
for $name in $p"
857 set exec [file join $p $name]
858 if {[file-isexec $exec]} {
859 dputs "Found
$name -> $exec"
867 # @find-executable name
869 # Searches the path for an executable with the given name.
870 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
871 # in which case the parameters are ignored.
872 # Returns 1 if found, or 0 if not.
874 proc find-executable {name} {
875 if {[find-executable-path $name] eq {}} {
881 # @find-an-executable ?-required? name ...
883 # Given a list of possible executable names,
884 # searches for one of these on the path.
886 # Returns the name found, or "" if none found.
887 # If the first parameter is '-required', an error is generated
888 # if no executable is found.
890 proc find-an-executable {args} {
892 if {[lindex $args 0] eq "-required"} {
893 set args [lrange $args 1 end]
897 if {[find-executable $name]} {
902 if {[llength $args] == 1} {
903 user-error "failed to
find: [join $args]"
905 user-error "failed to
find one of
: [join $args]"
913 # Writes the given message to the configuration log, 'config.log'.
915 proc configlog {msg} {
916 if {![info exists ::autosetup(logfh)]} {
917 set ::autosetup(logfh) [open config.log w]
919 puts $::autosetup(logfh) $msg
924 # Writes the message with no newline to stdout.
926 proc msg-checking {msg} {
927 if {$::autosetup(msg-quiet) == 0} {
930 set ::autosetup(msg-checking) 1
936 # Writes the message to stdout.
938 proc msg-result {msg} {
939 if {$::autosetup(msg-quiet) == 0} {
942 set ::autosetup(msg-checking) 0
947 # @msg-quiet command ...
949 # 'msg-quiet' evaluates it's arguments as a command with output
950 # from 'msg-checking' and 'msg-result' suppressed.
952 # This is useful if a check needs to run a subcheck which isn't
953 # of interest to the user.
954 proc msg-quiet {args} {
955 incr ::autosetup(msg-quiet)
956 set rc [uplevel 1 $args]
957 incr ::autosetup(msg-quiet) -1
961 # Will be overridden by 'use misc'
962 proc error-stacktrace {msg} {
966 proc error-location {msg} {
970 ##################################################################
975 if {$::autosetup(debug)} {
980 ##################################################################
982 # User and system warnings and errors
984 # Usage errors such as wrong command line options
988 # Indicate incorrect usage to the user, including if required components
989 # or features are not found.
990 # 'autosetup' exits with a non-zero return code.
992 proc user-error {msg} {
994 puts stderr "Error
: $msg"
995 puts stderr "Try
: '[file tail $::autosetup(exe)] --help' for options
"
1001 # Output the given message to stderr.
1003 proc user-notice {msg} {
1004 lappend ::autosetup(notices) $msg
1007 # Incorrect usage in the auto.def file. Identify the location.
1008 proc autosetup-error {msg} {
1009 autosetup-full-error [error-location $msg]
1012 # Like autosetup-error, except $msg is the full error message.
1013 proc autosetup-full-error {msg} {
1019 proc show-notices {} {
1020 if {$::autosetup(msg-checking)} {
1022 set ::autosetup(msg-checking) 0
1025 if {[info exists ::autosetup(notices)]} {
1026 puts stderr [join $::autosetup(notices) \n]
1027 unset ::autosetup(notices)
1031 proc maybe-show-timestamp {} {
1032 if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
1033 puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
1037 # @autosetup-require-version required
1039 # Checks the current version of 'autosetup' against '$required'.
1040 # A fatal error is generated if the current version is less than that required.
1042 proc autosetup-require-version {required} {
1044 if {[compare-versions $::autosetup(version) $required] < 0} {
1045 user-error "autosetup version
$required is required
, but this is $
::autosetup
(version
)"
1049 proc autosetup_version {} {
1050 return "autosetup v$
::autosetup
(version
)"
1053 ##################################################################
1055 # Directory/path handling
1058 proc realdir {dir} {
1066 # Follow symlinks until we get to something which is not a symlink
1067 proc realpath {path} {
1070 set path [file readlink $path]
1079 # Convert absolute path, $path into a path relative
1080 # to the given directory (or the current dir, if not given).
1082 proc relative-path {path {pwd {}}} {
1087 set path [file-normalize $path]
1091 set pwd [file-normalize $pwd]
1094 if {$path eq $pwd} {
1098 # Try to make the filename relative to the current dir
1099 foreach p [split $pwd /] f [split $path /] {
1107 # Add .. for sibling or parent dir
1115 if {$same == 1 || [llength $prefix] > 3} {
1119 file join [join $prefix /] [join $newf /]
1122 # Add filename as a dependency to rerun autosetup
1123 # The name will be normalised (converted to a full path)
1125 proc autosetup_add_dep {filename} {
1126 lappend ::autosetup(deps) [file-normalize $filename]
1129 ##################################################################
1131 # Library module support
1136 # Load the given library modules.
1137 # e.g. 'use cc cc-shared'
1139 # Note that module 'X' is implemented in either 'autosetup/X.tcl'
1140 # or 'autosetup/X/init.tcl'
1142 # The latter form is useful for a complex module which requires additional
1143 # support file. In this form, '$::usedir' is set to the module directory
1144 # when it is loaded.
1147 global autosetup libmodule modsource
1149 set dirs [list $autosetup(libdir)]
1150 if {[info exists autosetup(srcdir)]} {
1151 lappend dirs $autosetup(srcdir)/autosetup
1154 if {[info exists libmodule($m)]} {
1158 if {[info exists modsource(${m}.tcl)]} {
1159 automf_load eval $modsource(${m}.tcl)
1161 set locs [list ${m}.tcl ${m}/init.tcl]
1165 set source $dir/$loc
1166 if {[file exists $source]} {
1176 # For the convenience of the "use
" source, point to the directory
1177 # it is being loaded from
1178 set ::usedir [file dirname $source]
1179 automf_load source $source
1180 autosetup_add_dep $source
1182 autosetup-error "use
: No such module
: $m"
1188 proc autosetup_load_auto_modules {} {
1189 global autosetup modsource
1190 # First load any embedded auto modules
1191 foreach mod [array names modsource *.auto] {
1192 automf_load eval $modsource($mod)
1194 # Now any external auto modules
1195 foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
1196 automf_load source $file
1200 # Load module source in the global scope by executing the given command
1201 proc automf_load {args} {
1202 if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
1203 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
1208 set autosetup(exe) $::argv0
1209 set autosetup(istcl) 1
1210 set autosetup(start) [clock millis]
1211 set autosetup(installed) 0
1212 set autosetup(sysinstall) 0
1213 set autosetup(msg-checking) 0
1214 set autosetup(msg-quiet) 0
1215 set autosetup(inittypes) {}
1217 # Embedded modules are inserted below here
1218 set autosetup(installed) 1
1219 set autosetup(sysinstall) 0
1220 # ----- @module asciidoc-formatting.tcl -----
1222 set modsource(asciidoc-formatting.tcl) {
1223 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1224 # All rights reserved
1226 # Module which provides text formatting
1232 regsub -all "\
[ \t\n\
]+" [string trim $text] " "
1235 underline [para $text] =
1243 foreach line [parse_code_block $text] {
1248 proc codelines {lines} {
1249 foreach line $lines {
1257 proc underline {text char} {
1258 regexp "^
(\
[ \t\
]*)(.
*)" $text -> indent words
1260 puts $indent[string repeat $char [string length $words]]
1262 proc section {text} {
1263 underline "[para
$text]" -
1266 proc subsection {text} {
1270 proc bullet {text} {
1271 puts "* [para
$text]"
1273 proc indent {text} {
1277 proc defn {first args} {
1284 set defn [string trim [join $args \n]]
1285 regsub -all "\n\n" $defn "\n ::\n" defn
1290 # ----- @module formatting.tcl -----
1292 set modsource(formatting.tcl) {
1293 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1294 # All rights reserved
1296 # Module which provides common text formatting
1298 # This is designed for documenation which looks like:
1305 # In the second case, we need to work out the indenting
1306 # and strip it from all lines but preserve the remaining indenting.
1307 # Note that all lines need to be indented with the same initial
1310 # Returns a list of lines with the indenting removed.
1312 proc parse_code_block {text} {
1313 # If the text begins with newline, take the following text,
1314 # otherwise just return the original
1315 if {![regexp "^
\n(.
*)" $text -> text]} {
1316 return [list [string trim $text]]
1319 # And trip spaces off the end
1320 set text [string trimright $text]
1323 # Examine each line to determine the minimum indent
1324 foreach line [split $text \n] {
1326 # Ignore empty lines for the indent calculation
1329 regexp "^
(\
[ \t\
]*)" $line -> indent
1330 set len [string length $indent]
1336 # Now make a list of lines with this indent removed
1338 foreach line [split $text \n] {
1339 lappend lines [string range $line $min end]
1347 # ----- @module getopt.tcl -----
1349 set modsource(getopt.tcl) {
1350 # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
1351 # All rights reserved
1353 # Simple getopt module
1355 # Parse everything out of the argv list which looks like an option
1356 # Everything which doesn't look like an option, or is after --, is left unchanged
1357 # Understands --enable-xxx as a synonym for --xxx to enable the boolean option xxx.
1358 # Understands --disable-xxx to disable the boolean option xxx.
1360 # The returned value is a dictionary keyed by option name
1361 # Each value is a list of {type value} ... where type is "bool
" or "str
".
1362 # The value for a boolean option is 0 or 1. The value of a string option is the value given.
1363 proc getopt {argvname} {
1364 upvar $argvname argv
1369 for {set i 0} {$i < [llength $argv]} {incr i} {
1370 set arg [lindex $argv $i]
1377 lappend nargv {*}[lrange $argv $i end]
1381 if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
1383 dict lappend opts $name [list str $value]
1384 } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1385 if {$prefix in {enable- ""}} {
1390 dict lappend opts $name [list bool $value]
1396 #puts "getopt
: argv
=[join $argv] => [join $nargv]"
1397 #array set getopt $opts
1406 # ----- @module help.tcl -----
1408 set modsource(help.tcl) {
1409 # Copyright (c) 2010 WorkWare Systems http://workware.net.au/
1410 # All rights reserved
1412 # Module which provides usage, help and the command reference
1414 proc autosetup_help {what} {
1417 puts "Usage
: [file tail $
::autosetup
(exe
)] \
[options\
] \
[settings\
]\n"
1418 puts "This is
[autosetup_version
], a build environment
\"autoconfigurator
\""
1419 puts "See the documentation online
at http
://msteveb.github.com
/autosetup
/\n"
1421 if {$what eq "local"} {
1422 if {[file exists $::autosetup(autodef)]} {
1423 # This relies on auto.def having a call to 'options'
1424 # which will display options and quit
1425 source $::autosetup(autodef)
1430 incr ::autosetup(showhelp)
1431 if {[catch {use $what}]} {
1432 user-error "Unknown module
: $what"
1440 proc autosetup_show_license {} {
1441 global modsource autosetup
1444 if {[info exists modsource(LICENSE)]} {
1445 puts $modsource(LICENSE)
1448 foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
1449 set path [file join $dir LICENSE]
1450 if {[file exists $path]} {
1451 puts [readfile $path]
1455 puts "LICENSE not found
"
1458 # If not already paged and stdout is a tty, pipe the output through the pager
1459 # This is done by reinvoking autosetup with --nopager added
1461 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1463 exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
1465 if {[dict get $opts -errorcode] eq "NONE
"} {
1466 # an internal/exec error
1475 # Outputs the autosetup references in one of several formats
1476 proc autosetup_reference {{type text}} {
1480 switch -glob -- $type {
1481 wiki {use wiki-formatting}
1482 ascii* {use asciidoc-formatting}
1483 md - markdown {use markdown-formatting}
1484 default {use text-formatting}
1487 title "[autosetup_version
] -- Command Reference
"
1489 section {Introduction}
1492 See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
1496 'autosetup' provides a number of built-in commands which
1497 are documented below. These may be used from 'auto.def' to test
1498 for features, define variables, create files from templates and
1499 other similar actions.
1502 automf_command_reference
1507 proc autosetup_output_block {type lines} {
1508 if {[llength $lines]} {
1523 foreach line $lines {
1532 # Generate a command reference from inline documentation
1533 proc automf_command_reference {} {
1534 lappend files $::autosetup(prog)
1535 lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
1537 # We want to process all non-module files before module files
1538 # and then modules in alphabetical order.
1539 # So examine all files and extract docs into doc($modulename) and doc(_core_)
1541 # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
1542 # and $data is a string for section, subsection or a list of text lines for other types.
1544 # XXX: Should commands be in alphabetical order too? Currently they are in file order.
1547 lappend doc(_core_) [list section "Core Commands
"]
1549 foreach file $files {
1550 set modulename [file rootname [file tail $file]]
1556 # Find embedded module names
1557 if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
1561 # Find lines starting with "# @*" and continuing through the remaining comment lines
1562 if {![regexp
{^
# @(.*)} $line -> cmd]} {
1566 # Synopsis or command?
1567 if {$cmd eq
"synopsis:"} {
1568 set current
$modulename
1569 lappend doc
($current) [list section
"Module: $modulename"]
1571 lappend doc
($current) [list subsection
$cmd]
1577 # Now the description
1581 if {![regexp
{^
#(#)? ?(.*)} $line -> hash cmd]} {
1586 } elseif
{[regexp
{^
- (.
*)} $cmd -> cmd
]} {
1592 #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
1594 if {$t ne
$type ||
$cmd eq
""} {
1595 # Finish the current block
1596 lappend doc
($current) [list
$type $lines]
1605 lappend doc
($current) [list
$type $lines]
1610 # Now format and output the results
1612 # _core_ will sort first
1613 foreach module
[lsort
[array names doc
]] {
1614 foreach item
$doc($module) {
1615 autosetup_output_block
{*}$item
1621 # ----- @module init.tcl -----
1623 set modsource
(init.tcl
) {
1624 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1625 # All rights reserved
1627 # Module to help create auto.def and configure
1629 proc autosetup_init
{type} {
1631 if {$type in {?
help}} {
1633 } elseif
{![dict exists $
::autosetup
(inittypes
) $type]} {
1634 puts
"Unknown type, --init=$type"
1638 puts
"Use one of the following types (e.g. --init=make)\n"
1639 foreach
type [lsort
[dict keys $
::autosetup
(inittypes
)]] {
1640 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
1641 # XXX: Use the options-show code to wrap the description
1642 puts
[format
"%-10s %s" $type $desc]
1646 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
script
1648 puts
"Initialising $type: $desc\n"
1650 # All initialisations happens in the top level srcdir
1651 cd $
::autosetup
(srcdir
)
1656 proc autosetup_add_init_type
{type desc
script} {
1657 dict
set ::autosetup
(inittypes
) $type [list
$desc $script]
1660 # This is for in creating build-system init scripts
1662 # If the file doesn't exist, create it containing $contents
1663 # If the file does exist, only overwrite if --force is specified.
1665 proc autosetup_check_create
{filename contents
} {
1666 if {[file exists
$filename]} {
1667 if {!$
::autosetup
(force
)} {
1668 puts
"I see $filename already exists."
1671 puts
"I will overwrite the existing $filename because you used --force."
1674 puts
"I don't see $filename, so I will create it."
1676 writefile
$filename $contents
1680 # ----- @module install.tcl -----
1682 set modsource
(install.tcl
) {
1683 # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
1684 # All rights reserved
1686 # Module which can install autosetup
1688 # autosetup(installed)=1 means that autosetup is not running from source
1689 # autosetup(sysinstall)=1 means that autosetup is running from a sysinstall verion
1690 # shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
1692 proc autosetup_install
{dir
{shared
0}} {
1695 if {$autosetup(installed
) ||
$autosetup(sysinstall
)} {
1696 user-error
"Can only --sysinstall from development sources"
1698 } elseif
{$autosetup(installed
) && !$autosetup(sysinstall
)} {
1699 user-error
"Can't --install from project install"
1702 if {$autosetup(sysinstall
)} {
1703 # This is the sysinstall version, so install just uses references
1706 puts
"[autosetup_version] creating configure to use system-installed autosetup"
1707 autosetup_create_configure
1
1708 puts
"Creating autosetup/README.autosetup"
1709 file mkdir autosetup
1710 autosetup_install_readme autosetup
/README.autosetup
1
1716 set target
$dir/bin
/autosetup
1717 set installedas
$target
1720 set installedas autosetup
1722 set installedas
$dir/autosetup
1725 file mkdir autosetup
1726 set target autosetup
/autosetup
1728 set targetdir
[file dirname $target]
1729 file mkdir
$targetdir
1731 set f
[open
$target w
]
1733 set publicmodules
{}
1735 # First the main script, but only up until "CUT HERE"
1736 set in [open
$autosetup(dir
)/autosetup
]
1737 while {[gets
$in buf
] >= 0} {
1738 if {$buf ne
"##-- CUT HERE --##"} {
1743 # Insert the static modules here
1744 # i.e. those which don't contain @synopsis:
1745 # All modules are inserted if $shared is set
1746 puts
$f "set autosetup(installed) 1"
1747 puts
$f "set autosetup(sysinstall) $shared"
1748 foreach
file [lsort
[glob
$autosetup(libdir
)/*.
{tcl
,auto
}]] {
1749 set modname
[file tail $file]
1750 set ext
[file ext
$modname]
1751 set buf
[readfile
$file]
1753 if {$ext eq
".auto" ||
[string match
"*\n# @synopsis:*" $buf]} {
1754 lappend publicmodules
$file
1758 dputs
"install: importing lib/[file tail $file]"
1759 puts
$f "# ----- @module $modname -----"
1760 puts
$f "\nset modsource($modname) \{"
1765 foreach
{srcname destname
} [list
$autosetup(libdir
)/README.autosetup-lib README.autosetup \
1766 $autosetup(srcdir
)/LICENSE LICENSE
] {
1767 dputs
"install: importing $srcname as $destname"
1768 puts
$f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
1774 catch
{exec chmod 755 $target}
1776 set installfiles
{autosetup-config.guess autosetup-config.sub autosetup-test-tclsh
}
1780 autosetup_install_readme
$targetdir/README.autosetup
0
1782 # Install public modules
1783 foreach
file $publicmodules {
1784 set tail [file tail $file]
1785 autosetup_install_file
$file $targetdir/$tail
1787 lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
1788 lappend removefiles config.guess config.sub test-tclsh find-tclsh
1790 lappend installfiles
{sys-find-tclsh autosetup-find-tclsh
}
1793 # Install support files
1794 foreach fileinfo
$installfiles {
1795 if {[llength
$fileinfo] == 2} {
1796 lassign
$fileinfo source dest
1798 lassign
$fileinfo source
1801 autosetup_install_file
$autosetup(dir
)/$source $targetdir/$dest
1804 # Remove obsolete files
1805 foreach
file $removefiles {
1806 if {[file exists
$targetdir/$file]} {
1807 file delete
$targetdir/$file
1811 user-error
"Failed to install autosetup: $error"
1818 puts
"Installed $type [autosetup_version] to $installedas"
1821 # Now create 'configure' if necessary
1822 autosetup_create_configure
0
1826 proc autosetup_create_configure
{shared
} {
1827 if {[file exists configure
]} {
1828 if {!$
::autosetup
(force
)} {
1829 # Could this be an autosetup configure?
1830 if {![string match
"*\nWRAPPER=*" [readfile configure
]]} {
1831 puts
"I see configure, but not created by autosetup, so I won't overwrite it."
1832 puts
"Remove it or use --force to overwrite."
1836 puts
"I will overwrite the existing configure because you used --force."
1839 puts
"I don't see configure, so I will create it."
1842 writefile configure \
1844 # Note that WRAPPER is set here purely to detect an autosetup-created script
1845 WRAPPER
="-"; "autosetup" "$@"
1848 writefile configure \
1850 dir
="`dirname "$0"`/autosetup"
1851 WRAPPER
="$0"; export WRAPPER
; exec "`$dir/autosetup-find-tclsh`" "$dir/autosetup" "$@"
1854 catch
{exec chmod 755 configure
}
1857 # Append the contents of $file to filehandle $f
1858 proc autosetup_install_append
{f
file} {
1859 dputs
"install: include $file"
1865 proc autosetup_install_file
{source target
} {
1866 dputs
"install: $source => $target"
1867 if {![file exists
$source]} {
1868 error
"Missing installation file '$source'"
1870 writefile
$target [readfile
$source]\n
1871 # If possible, copy the file mode
1872 file stat
$source stat
1873 set mode
[format
%o
[expr {$stat(mode
) & 0x1ff}]]
1874 catch
{exec chmod $mode $target}
1877 proc autosetup_install_readme
{target sysinstall
} {
1878 set readme
"README.autosetup created by [autosetup_version]\n\n"
1881 {This is the autosetup directory
for a system
install of autosetup.
1882 Loadable modules can be added here.
1886 {This is the autosetup directory
for a
local install of autosetup.
1887 It contains autosetup
, support files and loadable modules.
1892 *.tcl files
in this directory are optional modules
which
1893 can be loaded with the
'use' directive.
1895 *.auto files
in this directory are auto-loaded.
1897 For
more information
, see http
://msteveb.github.com
/autosetup
/
1899 dputs
"install: autosetup/README.autosetup"
1900 writefile
$target $readme
1904 # ----- @module markdown-formatting.tcl -----
1906 set modsource
(markdown-formatting.tcl
) {
1907 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1908 # All rights reserved
1910 # Module which provides text formatting
1911 # markdown format (kramdown syntax)
1916 regsub
-all "\[ \t\n\]+" [string trim
$text] " " text
1917 regsub
-all {([^a-zA-Z
])'([^']*)'} $text {\1**`\2`**} text
1918 regsub -all {^'([^
']*)'} $text {**`\1`**} text
1919 regsub
-all {(http
[^
\t\n]*)} $text {[\
1](\
1)} text
1923 underline
[para
$text] =
1930 proc codelines
{lines
} {
1932 foreach line
$lines {
1940 foreach line
[parse_code_block
$text] {
1949 proc underline
{text char
} {
1950 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
1952 puts
$indent[string repeat
$char [string length
$words]]
1954 proc section
{text
} {
1955 underline
"[para $text]" -
1958 proc subsection
{text
} {
1962 proc bullet
{text
} {
1963 puts
"* [para $text]"
1965 proc defn
{first args
} {
1967 set defn
[string trim
[join $args \n]]
1970 puts
-nonewline ": "
1971 regsub
-all "\n\n" $defn "\n: " defn
1977 # ----- @module misc.tcl -----
1979 set modsource
(misc.tcl
) {
1980 # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
1981 # All rights reserved
1983 # Module containing misc procs useful to modules
1984 # Largely for platform compatibility
1986 set autosetup
(istcl
) [info exists
::tcl_library
]
1987 set autosetup
(iswin
) [string equal windows
$tcl_platform(platform
)]
1989 if {$autosetup(iswin
)} {
1990 # mingw/windows separates $PATH with semicolons
1991 # and doesn't have an executable bit
1992 proc split-path
{} {
1993 split [getenv PATH .
] {;}
1995 proc file-isexec
{exec} {
1996 # Basic test for windows. We ignore .bat
1997 if {[file isfile
$exec] ||
[file isfile
$exec.exe
]} {
2003 # unix separates $PATH with colons and has and executable bit
2004 proc split-path
{} {
2005 split [getenv PATH .
] :
2007 proc file-isexec
{exec} {
2008 file executable
$exec
2012 # Assume that exec can return stdout and stderr
2013 proc exec-with-stderr
{args
} {
2017 if {$autosetup(istcl
)} {
2018 # Tcl doesn't have the env command
2019 proc getenv
{name args
} {
2020 if {[info exists
::env
($name)]} {
2021 return $
::env
($name)
2023 if {[llength
$args]} {
2024 return [lindex
$args 0]
2026 return -code error
"environment variable \"$name\" does not exist"
2028 proc isatty?
{channel
} {
2029 dict exists
[fconfigure
$channel] -xchar
2032 if {$autosetup(iswin
)} {
2033 # On Windows, backslash convert all environment variables
2034 # (Assume that Tcl does this for us)
2035 proc getenv
{name args
} {
2036 string map
{\\ /} [env
$name {*}$args]
2039 # Jim on unix is simple
2042 proc isatty?
{channel
} {
2045 # isatty is a recent addition to Jim Tcl
2046 set tty
[$channel isatty
]
2052 # In case 'file normalize' doesn't exist
2054 proc file-normalize
{path
} {
2055 if {[catch
{file normalize
$path} result
]} {
2060 if {[file isdir
$path]} {
2064 cd [file dirname $path]
2065 set result
[file join [pwd] [file tail $path]]
2072 # If everything is working properly, the only errors which occur
2073 # should be generated in user code (e.g. auto.def).
2074 # By default, we only want to show the error location in user code.
2075 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
2077 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
2079 proc error-location
{msg
} {
2080 if {$
::autosetup
(debug
)} {
2081 return -code error
$msg
2083 # Search back through the stack trace for the first error in a .def file
2084 for {set i
1} {$i < [info level
]} {incr i
} {
2085 if {$
::autosetup
(istcl
)} {
2086 array
set info
[info frame
-$i]
2088 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
2090 if {[string match
*.def
$info(file)]} {
2091 return "[relative-path $info(file)]:$info(line): Error: $msg"
2093 #puts "Skipping $info(file):$info(line)"
2098 # If everything is working properly, the only errors which occur
2099 # should be generated in user code (e.g. auto.def).
2100 # By default, we only want to show the error location in user code.
2101 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
2103 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
2105 proc error-stacktrace
{msg
} {
2106 if {$
::autosetup
(debug
)} {
2107 return -code error
$msg
2109 # Search back through the stack trace for the first error in a .def file
2110 for {set i
1} {$i < [info level
]} {incr i
} {
2111 if {$
::autosetup
(istcl
)} {
2112 array
set info
[info frame
-$i]
2114 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
2116 if {[string match
*.def
$info(file)]} {
2117 return "[relative-path $info(file)]:$info(line): Error: $msg"
2119 #puts "Skipping $info(file):$info(line)"
2124 # Given the return from [catch {...} msg opts], returns an appropriate
2125 # error message. A nice one for Jim and a less-nice one for Tcl.
2126 # If 'fulltrace' is set, a full stack trace is provided.
2127 # Otherwise a simple message is provided.
2129 # This is designed for developer errors, e.g. in module code or auto.def code
2132 proc error-dump
{msg opts fulltrace
} {
2133 if {$
::autosetup
(istcl
)} {
2135 return "Error: [dict get $opts -errorinfo]"
2137 return "Error: $msg"
2140 lassign
$opts(-errorinfo) p f l
2142 set result
"$f:$l: Error: "
2144 append result
"$msg\n"
2146 append result
[stackdump
$opts(-errorinfo)]
2149 # Remove the trailing newline
2155 # ----- @module text-formatting.tcl -----
2157 set modsource
(text-formatting.tcl
) {
2158 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2159 # All rights reserved
2161 # Module which provides text formatting
2165 proc wordwrap
{text length
{firstprefix
""} {nextprefix
""}} {
2167 set space
$firstprefix
2169 foreach word
[split $text] {
2170 set word
[string trim
$word]
2174 if {[info exists partial
]} {
2175 append partial
" " $word
2176 if {[string first
$quote $word] < 0} {
2177 # Haven't found end of quoted word
2180 # Finished quoted word
2185 set quote
[string index
$word 0]
2186 if {$quote in {' *}} {
2187 if {[string first $quote $word 1] < 0} {
2188 # Haven't found end of quoted word
2190 set first
[string index
$word 0]
2191 # Start of quoted word
2198 if {$len && [string length
$space$word] + $len >= $length} {
2201 set space
$nextprefix
2203 incr len
[string length
$space$word]
2205 # Use man-page conventions for highlighting 'quoted' and *quoted*
2207 # Use x^Hx for *bold* and _^Hx for 'underline'.
2209 # less and more will both understand this.
2210 # Pipe through 'col -b' to remove them.
2211 if {[regexp
{^
'(.*)'(.
*)} $word -> quoted after
]} {
2212 set quoted
[string map
{~
" "} $quoted]
2213 regsub
-all .
$quoted "&\b&" quoted
2214 set word
$quoted$after
2215 } elseif
{[regexp
{^
[*](.
*)[*](.
*)} $word -> quoted after
]} {
2216 set quoted
[string map
{~
" "} $quoted]
2217 regsub
-all .
$quoted "_\b&" quoted
2218 set word
$quoted$after
2220 puts
-nonewline $space$word
2223 if {[info exists partial
]} {
2224 # Missing end of quote
2225 puts
-nonewline $space$partial
2232 underline
[string trim
$text] =
2239 proc codelines
{lines
} {
2240 foreach line
$lines {
2248 proc underline
{text char
} {
2249 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
2251 puts
$indent[string repeat
$char [string length
$words]]
2253 proc section
{text
} {
2254 underline
"[string trim $text]" -
2257 proc subsection
{text
} {
2261 proc bullet
{text
} {
2262 wordwrap
$text 76 " * " " "
2264 proc indent
{text
} {
2265 wordwrap
$text 76 " " " "
2267 proc defn
{first args
} {
2269 underline
" $first" ~
2279 # ----- @module util.tcl -----
2281 set modsource
(util.tcl
) {
2282 # Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
2283 # All rights reserved
2285 # Module which contains miscellaneous utility functions
2287 # @compare-versions version1 version2
2289 # Versions are of the form 'a.b.c' (may be any number of numeric components)
2291 # Compares the two versions and returns:
2296 # If one version has fewer components than the other, 0 is substituted to the right. e.g.
2301 proc compare-versions
{v1 v2
} {
2302 foreach c1
[split $v1 .
] c2
[split $v2 .
] {
2321 # Takes a list and returns a new list with '$suf' appended
2324 ## suffix .c {a b c} => {a.c b.c c.c}
2326 proc suffix
{suf list
} {
2329 lappend result
$p$suf
2336 # Takes a list and returns a new list with '$pre' prepended
2339 ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
2341 proc prefix
{pre list
} {
2344 lappend result
$pre$p
2350 # ----- @module wiki-formatting.tcl -----
2352 set modsource
(wiki-formatting.tcl
) {
2353 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2354 # All rights reserved
2356 # Module which provides text formatting
2357 # wiki.tcl.tk format output
2361 proc joinlines
{text
} {
2363 foreach l
[split [string trim
$text] \n] {
2364 lappend lines
[string trim
$l]
2369 puts
[joinlines
$text]
2373 puts
"*** [joinlines $text] ***"
2376 proc codelines
{lines
} {
2378 foreach line
$lines {
2385 foreach line
[parse_code_block
$text] {
2392 proc section
{text
} {
2396 proc subsection
{text
} {
2400 proc bullet
{text
} {
2401 puts
" * [joinlines $text]"
2403 proc indent
{text
} {
2404 puts
" : [joinlines $text]"
2406 proc defn
{first args
} {
2418 ##################################################################
2422 if {$autosetup(debug
)} {
2425 if {[catch
{main
$argv} msg opts
] == 1} {
2427 autosetup-full-error
[error-dump
$msg $opts $autosetup(debug
)]
2428 if {!$autosetup(debug
)} {
2429 puts stderr
"Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"