#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
use File::Find 'find';
use File::Basename 'basename';
use File::Glob 'bsd_glob';
sub read_file {
my $f = shift;
open my $fh, "<", $f or die "FATAL: read_rawfile() cannot open file '$f': $!";
binmode $fh;
return do { local $/; <$fh> };
}
sub write_file {
my ($f, $data) = @_;
die "FATAL: write_file() no data" unless defined $data;
open my $fh, ">", $f or die "FATAL: write_file() cannot open file '$f': $!";
binmode $fh;
print $fh $data or die "FATAL: write_file() cannot write to '$f': $!";
close $fh or die "FATAL: write_file() cannot close '$f': $!";
return;
}
sub sanitize_comments {
my($content) = @_;
$content =~ s{/\*(.*?)\*/}{my $x=$1; $x =~ s/\w/x/g; "/*$x*/";}egs;
return $content;
}
sub check_source {
my @all_files = (
bsd_glob("makefile*"),
bsd_glob("*.{h,c,sh,pl}"),
bsd_glob("*/*.{h,c,sh,pl}"),
);
my $fails = 0;
for my $file (sort @all_files) {
my $troubles = {};
my $lineno = 1;
my $content = read_file($file);
$content = sanitize_comments $content;
push @{$troubles->{crlf_line_end}}, '?' if $content =~ /\r/;
for my $l (split /\n/, $content) {
push @{$troubles->{merge_conflict}}, $lineno if $l =~ /^(<<<<<<<|=======|>>>>>>>)([^<=>]|$)/;
push @{$troubles->{trailing_space}}, $lineno if $l =~ / $/;
push @{$troubles->{tab}}, $lineno if $l =~ /\t/ && basename($file) !~ /^makefile/i;
push @{$troubles->{non_ascii_char}}, $lineno if $l =~ /[^[:ascii:]]/;
push @{$troubles->{cpp_comment}}, $lineno if $file =~ /\.(c|h)$/ && ($l =~ /\s\/\// || $l =~ /\/\/\s/);
# we prefer using MP_MALLOC, MP_FREE, MP_REALLOC, MP_CALLOC ...
push @{$troubles->{unwanted_malloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmalloc\s*\(/;
push @{$troubles->{unwanted_realloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\brealloc\s*\(/;
push @{$troubles->{unwanted_calloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bcalloc\s*\(/;
push @{$troubles->{unwanted_free}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bfree\s*\(/;
# and we probably want to also avoid the following
push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/;
push @{$troubles->{unwanted_memset}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemset\s*\(/;
push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/;
push @{$troubles->{unwanted_memmove}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemmove\s*\(/;
push @{$troubles->{unwanted_memcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcmp\s*\(/;
push @{$troubles->{unwanted_strcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcmp\s*\(/;
push @{$troubles->{unwanted_strcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcpy\s*\(/;
push @{$troubles->{unwanted_strncpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrncpy\s*\(/;
push @{$troubles->{unwanted_clock}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bclock\s*\(/;
push @{$troubles->{unwanted_qsort}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bqsort\s*\(/;
push @{$troubles->{sizeof_no_brackets}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bsizeof\s*[^\(]/;
if ($file =~ m|^[^\/]+\.c$| && $l =~ /^static(\s+[a-zA-Z0-9_]+)+\s+([a-zA-Z0-9_]+)\s*\(/) {
my $funcname = $2;
# static functions should start with s_
push @{$troubles->{staticfunc_name}}, "$lineno($funcname)" if $funcname !~ /^s_/;
}
$lineno++;
}
for my $k (sort keys %$troubles) {
warn "[$k] $file line:" . join(",", @{$troubles->{$k}}) . "\n";
$fails++;
}
}
warn( $fails > 0 ? "check-source: FAIL $fails\n" : "check-source: PASS\n" );
return $fails;
}
sub check_comments {
my $fails = 0;
my $first_comment = <<'MARKER';
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
MARKER
#my @all_files = (bsd_glob("*.{h,c}"), bsd_glob("*/*.{h,c}"));
my @all_files = (bsd_glob("*.{h,c}"));
for my $f (@all_files) {
my $txt = read_file($f);
if ($txt !~ /\Q$first_comment\E/s) {
warn "[first_comment] $f\n";
$fails++;
}
}
warn( $fails > 0 ? "check-comments: FAIL $fails\n" : "check-comments: PASS\n" );
return $fails;
}
sub check_doc {
my $fails = 0;
my $tex = read_file('doc/bn.tex');
my $tmh = read_file('tommath.h');
my @functions = $tmh =~ /\n\s*[a-zA-Z0-9_* ]+?(mp_[a-z0-9_]+)\s*\([^\)]+\)\s*;/sg;
my @macros = $tmh =~ /\n\s*#define\s+([a-z0-9_]+)\s*\([^\)]+\)/sg;
for my $n (sort @functions) {
(my $nn = $n) =~ s/_/\\_/g; # mp_sub_d >> mp\_sub\_d
if ($tex !~ /index\Q{$nn}\E/) {
warn "[missing_doc_for_function] $n\n";
$fails++
}
}
for my $n (sort @macros) {
(my $nn = $n) =~ s/_/\\_/g; # mp_iszero >> mp\_iszero
if ($tex !~ /index\Q{$nn}\E/) {
warn "[missing_doc_for_macro] $n\n";
$fails++
}
}
warn( $fails > 0 ? "check_doc: FAIL $fails\n" : "check-doc: PASS\n" );
return $fails;
}
sub prepare_variable {
my ($varname, @list) = @_;
my $output = "$varname=";
my $len = length($output);
foreach my $obj (sort @list) {
$len = $len + length $obj;
$obj =~ s/\*/\$/;
if ($len > 100) {
$output .= "\\\n";
$len = length $obj;
}
$output .= $obj . ' ';
}
$output =~ s/ $//;
return $output;
}
sub prepare_msvc_files_xml {
my ($all, $exclude_re, $targets) = @_;
my $last = [];
my $depth = 2;
# sort files in the same order as visual studio (ugly, I know)
my @parts = ();
for my $orig (@$all) {
my $p = $orig;
$p =~ s|/|/~|g;
$p =~ s|/~([^/]+)$|/$1|g;
my @l = map { sprintf "% -99s", $_ } split /\//, $p;
push @parts, [ $orig, join(':', @l) ];
}
my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } @parts;
my $files = "\r\n";
for my $full (@sorted) {
my @items = split /\//, $full; # split by '/'
$full =~ s|/|\\|g; # replace '/' bt '\'
shift @items; # drop first one (src)
pop @items; # drop last one (filename.ext)
my $current = \@items;
if (join(':', @$current) ne join(':', @$last)) {
my $common = 0;
$common++ while ($last->[$common] && $current->[$common] && $last->[$common] eq $current->[$common]);
my $back = @$last - $common;
if ($back > 0) {
$files .= ("\t" x --$depth) . "\r\n" for (1..$back);
}
my $fwd = [ @$current ]; splice(@$fwd, 0, $common);
for my $i (0..scalar(@$fwd) - 1) {
$files .= ("\t" x $depth) . "[$i]\"\r\n";
$files .= ("\t" x $depth) . "\t>\r\n";
$depth++;
}
$last = $current;
}
$files .= ("\t" x $depth) . "\r\n";
if ($full =~ $exclude_re) {
for (@$targets) {
$files .= ("\t" x $depth) . "\t\r\n";
$files .= ("\t" x $depth) . "\t\t \r\n";
$files .= ("\t" x $depth) . "\t \r\n";
}
}
$files .= ("\t" x $depth) . " \r\n";
}
$files .= ("\t" x --$depth) . " \r\n" for (@$last);
$files .= "\t ";
return $files;
}
sub patch_file {
my ($content, @variables) = @_;
for my $v (@variables) {
if ($v =~ /^([A-Z0-9_]+)\s*=.*$/si) {
my $name = $1;
$content =~ s/\n\Q$name\E\b.*?[^\\]\n/\n$v\n/s;
}
else {
die "patch_file failed: " . substr($v, 0, 30) . "..";
}
}
return $content;
}
sub process_makefiles {
my $write = shift;
my $changed_count = 0;
my @o = map { my $x = $_; $x =~ s/\.c$/.o/; $x } bsd_glob("*.c");
my @all = bsd_glob("*.{c,h}");
my $var_o = prepare_variable("OBJECTS", @o);
(my $var_obj = $var_o) =~ s/\.o\b/.obj/sg;
# update MSVC project files
my $msvc_files = prepare_msvc_files_xml(\@all, qr/NOT_USED_HERE/, ['Debug|Win32', 'Release|Win32', 'Debug|x64', 'Release|x64']);
for my $m (qw/libtommath_VS2008.vcproj/) {
my $old = read_file($m);
my $new = $old;
$new =~ s|.* |$msvc_files|s;
if ($old ne $new) {
write_file($m, $new) if $write;
warn "changed: $m\n";
$changed_count++;
}
}
# update OBJECTS + HEADERS in makefile*
for my $m (qw/ makefile makefile.shared makefile_include.mk makefile.msvc makefile.unix makefile.mingw /) {
my $old = read_file($m);
my $new = $m eq 'makefile.msvc' ? patch_file($old, $var_obj)
: patch_file($old, $var_o);
if ($old ne $new) {
write_file($m, $new) if $write;
warn "changed: $m\n";
$changed_count++;
}
}
if ($write) {
return 0; # no failures
}
else {
warn( $changed_count > 0 ? "check-makefiles: FAIL $changed_count\n" : "check-makefiles: PASS\n" );
return $changed_count;
}
}
sub draw_func
{
my ($deplist, $depmap, $out, $indent, $funcslist) = @_;
my @funcs = split ',', $funcslist;
# try this if you want to have a look at a minimized version of the callgraph without all the trivial functions
#if ($deplist =~ /$funcs[0]/ || $funcs[0] =~ /BN_MP_(ADD|SUB|CLEAR|CLEAR_\S+|DIV|MUL|COPY|ZERO|GROW|CLAMP|INIT|INIT_\S+|SET|ABS|CMP|CMP_D|EXCH)_C/) {
if ($deplist =~ /$funcs[0]/) {
return $deplist;
} else {
$deplist = $deplist . $funcs[0];
}
if ($indent == 0) {
} elsif ($indent >= 1) {
print {$out} '| ' x ($indent - 1) . '+--->';
}
print {$out} $funcs[0] . "\n";
shift @funcs;
my $olddeplist = $deplist;
foreach my $i (@funcs) {
$deplist = draw_func($deplist, $depmap, $out, $indent + 1, ${$depmap}{$i}) if exists ${$depmap}{$i};
}
return $olddeplist;
}
sub update_dep
{
#open class file and write preamble
open(my $class, '>', 'tommath_class.h') or die "Couldn't open tommath_class.h for writing\n";
print {$class} << 'EOS';
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
#define LTM_INSIDE
#if defined(LTM2)
# define LTM3
#endif
#if defined(LTM1)
# define LTM2
#endif
#define LTM1
#if defined(LTM_ALL)
EOS
foreach my $filename (glob 'bn*.c') {
my $define = $filename;
print "Processing $filename\n";
# convert filename to upper case so we can use it as a define
$define =~ tr/[a-z]/[A-Z]/;
$define =~ tr/\./_/;
print {$class} "# define $define\n";
# now copy text and apply #ifdef as required
my $apply = 0;
open(my $src, '<', $filename);
open(my $out, '>', 'tmp');
# first line will be the #ifdef
my $line = <$src>;
if ($line =~ /include/) {
print {$out} $line;
} else {
print {$out} << "EOS";
#include "tommath_private.h"
#ifdef $define
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
$line
EOS
$apply = 1;
}
while (<$src>) {
if ($_ !~ /tommath\.h/) {
print {$out} $_;
}
}
if ($apply == 1) {
print {$out} "#endif\n";
}
close $src;
close $out;
unlink $filename;
rename 'tmp', $filename;
}
print {$class} "#endif\n#endif\n";
# now do classes
my %depmap;
foreach my $filename (glob 'bn*.c') {
my $content;
if ($filename =~ "bn_deprecated.c") {
open(my $src, '<', $filename) or die "Can't open source file!\n";
read $src, $content, -s $src;
close $src;
} else {
my $cc = $ENV{'CC'} || 'gcc';
$content = `$cc -E -x c -DLTM_ALL $filename`;
$content =~ s/^# 1 "$filename".*?^# 2 "$filename"//ms;
}
# convert filename to upper case so we can use it as a define
$filename =~ tr/[a-z]/[A-Z]/;
$filename =~ tr/\./_/;
print {$class} "#if defined($filename)\n";
my $list = $filename;
# strip comments
$content =~ s{/\*.*?\*/}{}gs;
# scan for mp_* and make classes
my @deps = ();
foreach my $line (split /\n/, $content) {
while ($line =~ /(fast_)?(s_)?mp\_[a-z_0-9]*((?=\;)|(?=\())|(?<=\()mp\_[a-z_0-9]*(?=\()/g) {
my $a = $&;
next if $a eq "mp_err";
$a =~ tr/[a-z]/[A-Z]/;
$a = 'BN_' . $a . '_C';
push @deps, $a;
}
}
@deps = sort(@deps);
foreach my $a (@deps) {
if ($list !~ /$a/) {
print {$class} "# define $a\n";
}
$list = $list . ',' . $a;
}
$depmap{$filename} = $list;
print {$class} "#endif\n\n";
}
print {$class} << 'EOS';
#ifdef LTM_INSIDE
#undef LTM_INSIDE
#ifdef LTM3
# define LTM_LAST
#endif
#include "tommath_superclass.h"
#include "tommath_class.h"
#else
# define LTM_LAST
#endif
EOS
close $class;
#now let's make a cool call graph...
open(my $out, '>', 'callgraph.txt');
foreach (sort keys %depmap) {
draw_func("", \%depmap, $out, 0, $depmap{$_});
print {$out} "\n\n";
}
close $out;
return 0;
}
sub generate_def {
my @files = split /\n/, `git ls-files`;
@files = grep(/\.c/, @files);
@files = map { my $x = $_; $x =~ s/^bn_|\.c$//g; $x; } @files;
@files = grep(!/mp_radix_smap/, @files);
push(@files, qw(mp_set_int mp_set_long mp_set_long_long mp_get_int mp_get_long mp_get_long_long mp_init_set_int));
my $files = join("\n ", sort(grep(/^mp_/, @files)));
write_file "tommath.def", "; libtommath
;
; Use this command to produce a 32-bit .lib file, for use in any MSVC version
; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib
; Use this command to produce a 64-bit .lib file, for use in any MSVC version
; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib
;
EXPORTS
$files
";
return 0;
}
sub die_usage {
die <<"MARKER";
usage: $0 -s OR $0 --check-source
$0 -o OR $0 --check-comments
$0 -m OR $0 --check-makefiles
$0 -a OR $0 --check-all
$0 -u OR $0 --update-files
MARKER
}
GetOptions( "s|check-source" => \my $check_source,
"o|check-comments" => \my $check_comments,
"m|check-makefiles" => \my $check_makefiles,
"d|check-doc" => \my $check_doc,
"a|check-all" => \my $check_all,
"u|update-files" => \my $update_files,
"h|help" => \my $help
) or die_usage;
my $failure;
$failure ||= check_source() if $check_all || $check_source;
$failure ||= check_comments() if $check_all || $check_comments;
$failure ||= check_doc() if $check_doc; # temporarily excluded from --check-all
$failure ||= process_makefiles(0) if $check_all || $check_makefiles;
$failure ||= process_makefiles(1) if $update_files;
$failure ||= update_dep() if $update_files;
$failure ||= generate_def() if $update_files;
die_usage unless defined $failure;
exit $failure ? 1 : 0;
_7_a1_rc'>core_8_7_a1_rc
core_stabilizer_branch
core_stabilizer_merge_synthetic
core_zip_vfs
core_zip_vfs_c_encoder
core_zip_vfs_static
cpuid_on_unix
cygwin_environment_changes
dah_proc_arg_upvar
damkerngt_file_utime
daves_chop_branch
daves_mk_branch
dev_8_1_stubs_branch
dev_hobbs_branch
dev_stubs_branch
dgp_3401704
dgp_async_socket
dgp_bug_find
dgp_bye_ctx_eval_flag
dgp_bye_location_eval_list
dgp_channel_flag_repair
dgp_cmd_epoch
dgp_compile_list_shimmer
dgp_defer_string_rep
dgp_demo
dgp_dup_encoding_fix
dgp_ecr
dgp_encoding_flags
dgp_ensemble_rewrite
dgp_eof
dgp_experiment
dgp_flush_channel
dgp_hoehrmann_decoder
dgp_init_bytecode
dgp_list_simplify
dgp_literal_reform
dgp_may_be_pointless
dgp_move_buffers
dgp_no_buffer_recycle
dgp_optimize_output_stage
dgp_pkg_migration
dgp_properbytearray
dgp_purge_NRRunObjProc
dgp_read_bytes
dgp_read_bytes_detour
dgp_read_chars
dgp_refactor
dgp_refactor_merge_synthetic
dgp_remove_string_result
dgp_review
dgp_revise_parsedvarnametype
dgp_scan_element
dgp_slow_read
dgp_sprintf
dgp_stack_depth_tester
dgp_stackedstdchan
dgp_stop_regexp_test_crash
dgp_string_cat
dgp_string_find
dgp_stringcat_delaystringrep
dgp_switch_compile
dgp_tailcall_errorinfo
dgp_tailcall_errorinfo_alt
dgp_tcs_rewrite
dgp_thread_leaks
dgp_trunk_flag_repair
dgp_trunk_read
dgp_win_specific_strict
dgp_writebytes_optimize
dkf_64bit_support_branch
dkf_alias_encoding
dkf_asm_crash_20131022
dkf_bcc_optimize
dkf_better_try_compilation
dkf_bytecode_8_6
dkf_bytecode_8_6_eval
dkf_bytecode_8_6_join
dkf_bytecode_8_6_next
dkf_bytecode_8_6_string_is
dkf_bytecode_8_6_string_replace
dkf_bytecode_8_6_yield
dkf_bytecode_optimizer
dkf_command_type
dkf_compile_improvements
dkf_dict_with_compiled
dkf_documentation_figures
dkf_expose_ptrgetvar
dkf_expose_ptrgetvar_8_6
dkf_http_cookies
dkf_improved_disassembler
dkf_loop_exception_range_work
dkf_namespace_as_ensemble
dkf_notifier_poll
dkf_oo_override_definition_namespaces
dkf_quieter_compiles
dkf_review
dkf_utf16_branch
dkf_wait_with_poll
dogeen_assembler_branch
dogeen_assembler_merge_synthetic
drh_micro_optimization
editorconfig
empty_bodies
experiment
experimental
ferrieux_nacl
fix_1997007
fix_42202ba1e5ff566e
fix_8_5_578155d5a19b348d
fix_win_native_access
fix_windows_zlib
forgiving_pkgconfig
freq_3010352_impl
frq_3527238
frq_3544967
frq_3579001
frq_3599786
gahr_split_install
gahr_ticket_dee3d66bc7
gahr_ticket_e6f27aa56f
gahr_tip_447
griffin_numlevels
htmlCopyrightsFix
htmlhelpFix
http3
hypnotoad
hypnotoad_bug_3598385
hypnotoad_prefer_native_8_6
hypnotoad_vexpr
info_linkedname
initsubsystems
initsubsystems2
initsubsystems2_split
iocmd_leaks
ios
irontcl
jcr_notifier_poll
je_tty_cleanup
jenglish_termios_cleanup
jn_0d_radix_prefix
jn_Tcl_requirement
jn_emptystring
jn_frq_3257396
jn_no_struct_names
jn_unc_vfs
jn_wide_printf
kbk_clock_encoding_ensembles
kennykb_numerics_branch
kennykb_tip_22_33
kennykb_tip_22_33_botched
lanam_array_for_impl
libtommath
libtommath_1_0
libtommath_1_0_1
libtommath_tcl_fixes_75
little
macosx_8_4_branch
master
merge_tzdata_to_trunk
micro_opt
mig_alloc_reform
mig_catch_compiler
mig_err
mig_no280
mig_nre_mods
mig_opt2
mig_opt2_tmp
mig_opt_foreach
mig_optimize
mig_review
mig_stacklevels
mig_strip_brutal
mig_tailcall_cleanup
mig_tmp
mig_tmp_optimize
minimal_fix_for_3598300_problems
miniz
mistachkin_review
mistake
mistake_20110314
mistake_20110314a
mistkae
mod_8_3_4_branch
more_macros
msgcat_dyn_locale
msofer_bcEngine
msofer_wcodes_branch
msvc_with_64bit_zlib1_dll
no_shimmer_string_length
no_smartref
nonmonotonic_obj_alloc
notifier
novem
novem_64bit_sizes
novem_ak_iframe_direct
novem_ak_preserve_experiments
novem_bighash
novem_bug_3598300
novem_demo_bug_3588687
novem_freeifrefcountzero
novem_more_memory_API
novem_no_register_objtypes
novem_no_shimmer_string_length
novem_no_startcmd
novem_numbers_eias
novem_purge_literals
novem_reduced_bytecodes
novem_reduced_symbol_export
novem_remove_string_result
novem_remove_va
novem_rename_memory_API
novem_review
novem_saveresult_as_macro
novem_support
novem_two_layer_list
novem_unversioned_stub
off_8_4_branch
off_trunk
on_hold_84
on_hold_85
on_hold_trunk
oo_copy_ns
other_64bit_candidates
package_files
panic_noreturn
prevent_inline
private
pseudotrunk_2011_03_08
pyk_emptystring
pyk_expr_numeric
pyk_listdictstringrep
pyk_pkgrequirenre
pyk_trunk
remove_pathappend_intrep
remove_trim_header
revert_3396731
rfe_1711975
rfe_3216010
rfe_3389978
rfe_3432962
rfe_3464401
rfe_3473670
rfe_6c0d7aec67
rfe_854941
rfe_b42b208ba4
rfe_dfc08326e3
rfe_notifier_fork
rmax_ipv6_branch
rmax_ipv6_merge_synthetic
robust_async_connect_tests
scriptics_sc_1_0_branch
scriptics_sc_1_1_branch
scriptics_sc_2_0_b2_synthetic
scriptics_sc_2_0_b5_synthetic
scriptics_sc_2_0_fixed_synthetic
scriptics_tclpro_1_2
scriptics_tclpro_1_2_old
scriptics_tclpro_1_2_synthetic
scriptics_tclpro_1_3_b2_branch
scriptics_tclpro_1_3_b3_synthetic
sebres_8_5_event_perf_branch
sebres_8_5_timerate
sebres_8_6_clock_speedup
sebres_8_6_clock_speedup_cr1
sebres_8_6_event_perf_branch
sebres_8_6_timerate
sebres_clean_core_8_5
sebres_clock_speedup
sebres_clock_tz_fix
sebres_event_perf_fix_busy_wait
sebres_optimized_8_5
sebres_trunk_clock_speedup
sebres_trunk_timerate
semver
stwo_dev86
tclPlatformEngine
tcl_nosize
tclchan_assertions
tclpro_1_5_0_synthetic
tcltest_verbose_desc
tgl_pg_re
thread_leaks
ticket_9b2e636361
ticket_e770d92d6
tip280_test_coverage
tip404_tcl8_5
tip429_only_id
tip_106_impl
tip_162_branch
tip_257_implementation_branch
tip_257_implementation_branch_root_synthetic
tip_257_merge1_branch_20061020T1300
tip_278_branch
tip_282
tip_302
tip_312
tip_318_update
tip_388_impl
tip_389_impl
tip_395_with_alt_name
tip_398_impl
tip_400_impl
tip_401
tip_404
tip_405_impl_td
tip_427
tip_428
tip_429
tip_436
tip_440_alt
tip_440_backport
tip_444
tip_445
tip_445_fork
tip_445_reject
tip_452
tip_456
tip_456_fork
tip_457
tip_458
tip_458_experiment
tip_463
tip_465
tip_468
tip_468_bis
tip_469
tip_470
tip_473
tip_59_implementation
tip_improve_exec
tk_bug_9eb55debc5
tkt3328635_posix_monotonic_clock
tkt_04e26c02c0
tkt_414d10346b
tkt_4d5ae7d88a
unbreak_tclcompiler
unknown_rewrite
unproven
unsetThreadData
unwanted
updateextended
vc_reform
vs_ide_compile
werner_utf_max_6
win32_arm
winFixes
win_console_panic
win_sock_async_connect_race_fix
z_modifier
zipfs
zippy_fifo
zlib_1_2_6
Tcl is a high-level, general-purpose, interpreted, dynamic programming language. It was designed with the goal of being very simple but powerful.
blob: d23235a2ea1150968e600422e2aeaf2f02f27b7c (
plain )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Notes about the Background Only application template
====================================================
RCS: @(#) $Id: Background.doc,v 1.2 1998/09/14 18:40:03 stanton Exp $
We have included sample code and project files for making a Background-Only
application (BOA) in Tcl. This could be used for server processes (like the
Tcl Web-Server).
Files:
------
* BOA_TclShells.¼ - This is the project file.
* tclMacBOAAppInit.c - This is the AppInit file for the BOA App.
* tclMacBOAMain - This is a replacement for the Tcl_Main for BOA's.
Caveat:
-------
This is an unsupported addition to MacTcl. The main feature that will certainly
change is how we handle AppleEvents. Currently, all the AppleEvent handling is
done on the Tk side, which is not really right. Also, there is no way to
register your own AppleEvent handlers, which is obviously something that would be
useful in a BOA App. We will address these issues in Tcl8.1. If you need to
register your own AppleEvent Handlers in the meantime, be aware that your code
will probably break in Tcl8.1.
I will also improve the basic code here based on feedback that I recieve. This
is to be considered a first cut only at writing a BOA in Tcl.
Introduction:
-------------
This project makes a double-clickable BOA application. It obviously needs
some Tcl code to get it started. It will look for this code first in a
'TEXT' resource in the application shell whose name is "bgScript.tcl". If
it does not find any such resource, it will look for a file called
bgScript.tcl in the application's folder. Otherwise it will quit with an
error.
It creates three files in the application folder to store stdin, stdout &
stderr. They are imaginatively called temp.in, temp.out & temp.err. They
will be opened append, so you do not need to erase them after each use of
the BOA.
The app does understand the "quit", and the "doScript" AppleEvents, so you can
kill it with the former, and instruct it with the latter. It also has an
aete, so you can target it with Apple's "Script Editor".
For more information on Macintosh BOA's, see the Apple TechNote: 1070.
Notifications:
--------------
BOA's are not supposed to have direct contact with the outside world. They
are, however, allowed to go through the Notification Manager to post
alerts. To this end, I have added a Tcl command called "bgnotify" to the
shell, that simply posts a notification through the notification manager.
To use it, say:
bgnotify "Hi, there little buddy"
It will make the system beep, and pop up an annoying message box with the
text of the first argument to the command. While the message is up, Tcl
is yielding processor time, but not processing any events.
Errors:
-------
Usually a Tcl background application will have some startup code, opening
up a server socket, or whatever, and at the end of this, will use the
vwait command to kick off the event loop. If an error occurs in the
startup code, it will kill the application, and a notification of the error
will be posted through the Notification Manager.
If an error occurs in the event handling code after the
vwait, the error message will be written to the file temp.err. However,
if you would like to have these errors post a notification as well, just
define a proc called bgerror that takes one argument, the error message,
and passes that off to "bgnotify", thusly:
proc bgerror {mssg} {
bgnotify "A background error has occured\n $mssg"
}
Support:
--------
If you have any questions, contact me at:
jim.ingham@eng.sun.com