# The public interface to makelib's tools mechanism.
# (This generic must be expanded after the rest of makelib is
# already in place because it uses load_plugin.)
#
# (C) 2000 Lucent Technologies, Bell Laboratories
#
# Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp)
# Compiled by:
#
src/app/makelib/makelib.sublib
# private_makelib_tools is from
src/app/makelib/tools/main/private-makelib-tools.pkg # winix__premicrothread is from
src/lib/std/winix--premicrothread.pkgstipulate
package ad = anchor_dictionary; # anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg package cj = global_control_junk; # global_control_junk is from
src/lib/global-controls/global-control-junk.pkg package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkg package mld = makelib_defaults; # makelib_defaults is from
src/app/makelib/stuff/makelib-defaults.pkg package sub = string_substitution; # string_substitution is from
src/app/makelib/stuff/string-substitution.pkgherein
# This generic invoked in:
#
src/app/makelib/main/makelib-g.pkg #
generic package tools_g (
#
load_plugin' : anchor_dictionary::File -> Bool;
anchor_dictionary: anchor_dictionary::Anchor_Dictionary;
)
: (weak)
Tools # Tools is from
src/app/makelib/tools/main/public-tools.api {
include package private_makelib_tools; # Moving this into the outer stipulate is a pain; most of the components are re-exported via api Tools.
say = fil::say; # Exported to clients.
# Find the executable binary for this command.
# There are three cases:
#
# /bin/foo is interpreted as an abosolute path.
#
# bin/foo is interpreted as a path relative
# to anchor_dictionary::get_anchor "ROOT"
#
# foo is interpreted as $foo/foo
# if foo is a defined anchor.
#
# The result of this function SHOULD NOT be cached.
# Otherwise a later addition or change of an anchor
# will go unnoticed.
#
fun resolve_command_path
file # command as a standard path.
=
if (string::get_byte_as_char (file, 0) == '/') # Does path start with '/'?
#
file; # Yes, use it as-is
else
case (ad::get_anchor # Is it defined as an anchor?
( anchor_dictionary,
file
))
THE dir # Yes, treat it as $foo/foo
=>
winix__premicrothread::path::make_path_from_dir_and_file { dir, file };
NULL # No, treat it as $ROOT/foo
=>
(the (ad::get_anchor( anchor_dictionary, "ROOT"))) + "/" + file;
esac;
fi;
fun note_standard_shell_command_tool
args
=
{ args -> { tool,
ilk,
suffixes,
command_standard_path,
extension_style,
template,
dflopts
};
template = the_else (template, "%c %u %s");
fun err m
=
raise exception TOOL_ERROR { tool, msg => m };
fun rule { spec, context, native2pathmaker, default_ilk_of, sysinfo }
=
{ spec -> { name, make_path, tool_options, derived, ... } : Spec;
opts = the_else (tool_options, dflopts);
sol = list::map_partial_fn so opts
where
fun so (SUBOPTS _) => NULL; # only use STRING options for %o
so (STRING s) => THE (native_spec (srcpath (s.make_path ())));
end;
end;
# list is from
src/lib/std/src/list.pkg p = srcpath (make_path ());
native_name = native_spec p;
tfiles = extend_filename extension_style (native_name, tool_options);
partial_expansion
=
( { source_files => [],
makelib_files => [],
sources => [(p, { ilk, derived } )]
},
map (\\ (name, ilk, tool_options)
=
{ name,
ilk,
tool_options,
derived => TRUE,
make_path => native2pathmaker name
}
)
tfiles
);
fun run_command ()
=
{ (command_standard_path ())
->
(csp, shelloptions); # "csp" == "command as a standard path" -- see "resolve_command_path" comments.
command_path = resolve_command_path csp;
cmd = sub::substitute
[
{ prefix => "%",
substitutions
=>
[ sub::subfor "%c" command_path,
sub::subfor "%s" native_name,
sub::subfor "%%" "%",
sub::subnsel (1, 'o', \\ x = x, " ") sol,
sub::subnsel (1, 't', #1, " ") tfiles,
sub::subnsel (1, 'u', \\ x = x, " ") shelloptions
]
}
]
template;
include package winix__premicrothread::process;
#
if (bin_sh' cmd != success) err cmd; fi;
};
fun rulefn ()
=
{ if (outdated tool (map #1 tfiles, native_name))
#
run_command ();
fi;
partial_expansion;
};
context rulefn;
};
fun do_suffix suffix
=
note_filename_classifier (standard_filename_suffix_classifier { suffix, ilk } );
note_ilk (ilk, rule);
apply do_suffix suffixes;
};
stipulate
tool_ilk = "tool";
suffix_ilk = "suffix";
empty_expansion
=
( { makelib_files => [],
source_files => [],
sources => []
},
[]
);
fun tool_rule { spec, context, native2pathmaker, default_ilk_of, sysinfo }
=
{ spec -> { name, make_path, tool_options, ... } : Spec;
fun err m
=
raise exception TOOL_ERROR { tool => tool_ilk, msg => m };
p = srcpath (make_path ());
case tool_options
#
NULL => if (with_plugin p (\\ () = load_plugin' p))
#
empty_expansion;
else
err "tool registration failed";
fi;
THE _ => err "no tool options are recognized";
esac;
};
fun suffix_rule { spec, context, native2pathmaker, default_ilk_of, sysinfo }
=
{ spec -> { name => suffix, tool_options, ... } : Spec;
fun err m
=
raise exception TOOL_ERROR { tool => suffix_ilk, msg => m };
fun note ilk
=
{ note_filename_classifier
(standard_filename_suffix_classifier { suffix, ilk } );
empty_expansion;
};
case tool_options
#
THE [STRING c]
=>
note c.name;
THE [SUBOPTS { name => "ilk", tool_options => [STRING c] } ]
=>
note c.name;
_ => err "invalid options";
esac;
};
herein
my _ =
note_ilk (tool_ilk, tool_rule); my _ =
note_ilk (suffix_ilk, suffix_rule);
end;
fun make_boolean_control (name, doc, default)
=
mld::make_control
(
cj::cvt::bool,
name,
doc,
default
);
};
end;