%%% BEGIN pibfi_options.erl %%% %%% %%% pibfi - Platonic Ideal Brainf*ck Interpreter %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved. %%% %%% Redistribution and use in source and binary forms, with or without %%% modification, are permitted provided that the following conditions %%% are met: %%% %%% Redistributions of source code must retain the above copyright %%% notice, this list of conditions and the following disclaimer. %%% %%% Redistributions in binary form must reproduce the above copyright %%% notice, this list of conditions and the following disclaimer in %%% the documentation and/or other materials provided with the %%% distribution. %%% %%% Neither the name of Cat's Eye Technologies nor the names of its %%% contributors may be used to endorse or promote products derived %%% from this software without specific prior written permission. %%% %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %%% POSSIBILITY OF SUCH DAMAGE. %% @doc Options parser for pibfi. %% %%

Synopsis

%% %%

This module implements collecting options %% from the command line.

%% %%

When invoking pibfi from the command line, the %% following syntax can be used:

%% %% %% %%

The following options are recognized.

%% %% %% %% @end -module(pibfi_options). -vsn('2003.0505'). -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.'). -export([get_flag/1, get_opts/1]). -export([get_option/3]). %% @spec get_flag(Switch::atom()) -> true | false %% @doc Gets a switch from the command line. get_flag(Option) -> case init:get_argument(Option) of {ok, [X]} -> true; error -> false end. %% @spec get_opts([atom()]) -> [{atom(), term()}] %% @doc Gets a set of options from the command line. get_opts(Options) -> lists:foldl(fun(Option, Acc) when is_atom(Option) -> case init:get_argument(Option) of error -> Acc; {ok, [[]]} -> [{Option, missing(Option)} | Acc]; {ok, [[Arg | _] | _]} -> [{Option, convert(Option, Arg)} | Acc] end; ({Option, Default}, Acc) -> case init:get_argument(Option) of error -> [{Option, Default} | Acc]; {ok, [[]]} -> [{Option, missing(Option)} | Acc]; {ok, [[Arg | _] | _]} -> [{Option, convert(Option, Arg)} | Acc] end end, [], Options). %% @spec missing(atom()) -> term() %% @doc Gets the default value for an option specified with no value %% on the command line. missing(wrapcell) -> true; missing(wraptape) -> true; missing(wrapout) -> true; missing(wrapin) -> true; missing(xlatin) -> []; missing(xlatout) -> []; missing(dontstrip) -> lists:seq(0, 255); missing(optimize) -> 1; missing(statuscmd) -> "#"; missing(heredoc) -> "!"; missing(Else) -> exit({missing_parameter_for, Else}). %% @spec convert(atom(), string()) -> term() %% @doc Converts an option value specified on the command line to a %% term that pibfi can work with internally. convert(dontstrip, String) -> unescape(String); convert(optimize, Integer) -> list_to_integer(Integer); convert(statuscmd, "undefined") -> undefined; convert(statuscmd, String) -> unescape(String); convert(heredoc, "undefined") -> undefined; convert(heredoc, String) -> unescape(String); convert(tapemodule, String) -> list_to_atom(String); convert(maxcell, "infinity") -> infinity; convert(maxcell, Else) -> list_to_integer(Else); convert(mincell, "infinity") -> infinity; convert(mincell, Else) -> list_to_integer(Else); convert(wrapcell, "true") -> true; convert(wrapcell, "false") -> false; convert(maxtape, "infinity") -> infinity; convert(maxtape, Else) -> list_to_integer(Else); convert(mintape, "infinity") -> infinity; convert(mintape, Else) -> list_to_integer(Else); convert(wraptape, "true") -> true; convert(wraptape, "false") -> false; convert(infile, "tty") -> tty; convert(infile, "heredoc") -> heredoc; convert(infile, Else) -> Else; convert(outfile, "tty") -> tty; convert(outfile, Else) -> Else; convert(maxout, "infinity") -> infinity; convert(maxout, Else) -> list_to_integer(Else); convert(minout, "infinity") -> infinity; convert(minout, Else) -> list_to_integer(Else); convert(wrapout, "true") -> true; convert(wrapout, "false") -> false; convert(maxin, "infinity") -> infinity; convert(maxin, Else) -> list_to_integer(Else); convert(minin, "infinity") -> infinity; convert(minin, Else) -> list_to_integer(Else); convert(wrapin, "true") -> true; convert(wrapin, "false") -> false; convert(xlatin, String) -> parse_xlat(String, []); convert(xlatout, String) -> parse_xlat(String, []); convert(eof, "halt") -> halt; convert(eof, "nop") -> nop; convert(eof, "stop") -> stop; convert(eof, Else) -> list_to_integer(Else); convert(statusevery, "undefined") -> undefined; convert(statusevery, Else) -> Factor = case lists:last(Else) of $s -> 1000; $m -> 60*1000; $h -> 60*60*1000; _ -> 1 end, Root = case Factor of 1 -> Else; _ -> lists:reverse(tl(lists:reverse(Else))) end, % ce_log:write("~p ~p", [Root, Factor]), list_to_integer(Root) * Factor. parse_xlat(String, Acc) -> {First, String0} = parse_lstring(String, ""), {Second, String1} = parse_rstring(String0, ""), pibfi:assert(First =/= "", {lefthand_string_in_xlat_may_not_be_null, String}), Acc0 = [{unescape(First), unescape(Second)} | Acc], case String1 of "," ++ String2 -> parse_xlat(String2, Acc0); _ -> Acc0 end. parse_lstring("=" ++ Tail, Acc) -> {lists:reverse(Acc), Tail}; parse_lstring([Head | Tail], Acc) -> parse_lstring(Tail, [Head | Acc]). parse_rstring("", Acc) -> {lists:reverse(Acc), ""}; parse_rstring("," ++ Tail, Acc) -> {lists:reverse(Acc), "," ++ Tail}; parse_rstring([Head | Tail], Acc) -> parse_rstring(Tail, [Head | Acc]). %% @spec unescape(string()) -> string() %% @doc Transforms escape codes in a string into embedded characters. %% The escape code #i where i is a %% decimal integer of from one to three digits is converted into an %% ASCII character of that value. unescape(String) -> unescape(String, []). unescape([], Acc) -> lists:reverse(Acc); unescape([$#, $n, $l | Tail], Acc) -> unescape(Tail, lists:reverse(pibfi:os_eol()) ++ Acc); unescape([$#, D1, D2, D3 | Tail], Acc) when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9, D3 >= $0, D3 =< $9 -> unescape(Tail, [(D1 - $0) * 100 + (D2 - $0) * 10 + (D3 - $0) | Acc]); unescape([$#, D1, D2 | Tail], Acc) when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9 -> unescape(Tail, [(D1 - $0) * 10 + (D2 - $0) | Acc]); unescape([$#, D | Tail], Acc) when D >= $0, D =< $9 -> unescape(Tail, [(D - $0) | Acc]); unescape([Head | Tail], Acc) -> unescape(Tail, [Head | Acc]). %% @spec get_option(Options::[{atom(), term()}], Option::atom(), Default::term()) -> term() %% @doc Gets an option from a list of (already parsed) option tuples. get_option(TupleList, Option, Default) -> case lists:keysearch(Option, 1, TupleList) of {value, {Option, Value}} -> Value; _ -> Default end. %%% END of pibfi_options.erl %%%