aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/slang.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/slang.erl')
-rw-r--r--src/slang.erl644
1 files changed, 644 insertions, 0 deletions
diff --git a/src/slang.erl b/src/slang.erl
new file mode 100644
index 0000000..eca5507
--- /dev/null
+++ b/src/slang.erl
@@ -0,0 +1,644 @@
+%%% FILE : slang.erl
+%%% Author : Claes Wikstrom <klacke@kaja.hemma.net>
+%%% Purpose : interface to the cool multi platform tty slang lib
+%%% Created : 22 Nov 2000 by Claes Wikstrom <klacke@kaja.hemma.net>
+%%%----------------------------------------------------------------------
+
+-module(slang).
+-author('klacke@kaja.hemma.net').
+
+-include("../include/slang.hrl").
+-include("slang_int.hrl").
+
+-compile(export_all).
+
+
+stop_user() ->
+ Flag=process_flag(trap_exit, true),
+ {links, Lks0} = process_info(whereis(user),links),
+ Lks = lists:delete(whereis(error_logger), Lks0),
+
+ Hs = gen_event:which_handlers(error_logger),
+
+ case lists:member(error_logger_tty_h, Hs) of
+ true ->
+ error_logger:delete_report_handler(error_logger_tty_h),
+
+
+ supervisor:terminate_child(kernel_sup, user),
+ lists:foreach(fun(Pid) ->
+ exit(Pid, kill)
+ end, Lks),
+ {stopdata, true};
+ false ->
+ {stopdata, false}
+ end.
+
+
+restart_user({stopdata, TTY_H}) ->
+ case TTY_H of
+ true ->
+ supervisor:restart_child(kernel_sup, user),
+ wait_user(whereis(user)),
+ error_logger:add_report_handler(error_logger_tty_h);
+ false ->
+ supervisor:restart_child(kernel_sup, user)
+ end.
+
+
+%% restart chaild ain't synced
+wait_user(undefined) ->
+ timer:sleep(200),
+ wait_user(whereis(user));
+wait_user(_) ->
+ ok.
+
+
+init_tty(AbortChar, FlowControl, Opost) ->
+ P = gp(),
+ p_cmd(P, ?INIT_TTY, [{int, AbortChar},
+ {int, FlowControl},
+ {int, Opost}], int32).
+
+set_abort_signal(null) ->
+ P = gp(),
+ p_cmd(P, ?SET_ABORT_SIGNAL, [{int, 0}], int32).
+
+getkey() ->
+ P = gp(),
+ p_cmd(P, ?GETKEY, [], int32).
+
+kp_getkey() ->
+ P = gp(),
+ p_cmd(P, ?KP_GETKEY, [], int32).
+
+
+kp_init() ->
+ P = gp(),
+ p_cmd(P, ?KP_INIT, [], int32).
+
+reset_tty() ->
+ P = gp(),
+ p_cmd(P, ?RESET_TTY, [], void).
+
+
+ungetkey(Char) ->
+ P = gp(),
+ p_cmd(P, ?GETKEY, [{char, Char}], void).
+
+
+%% read slang lib global variables
+getvar(Var) when atom(Var) ->
+ P = gp(),
+ p_cmd(P, ?GETVAR, [{int, encode_var(Var)}], int).
+
+%% set slang lib global variables
+setvar(Var, IntegerValue) when atom(Var) ->
+ P = gp(),
+ p_cmd(P, ?SETVAR, [{int, encode_var(Var)}, {int, IntegerValue}], void).
+
+
+isatty(Fd) ->
+ P = gp(),
+ p_cmd(P, ?ISATTY, [{int, Fd}], int).
+
+eformat(Fmt, Args) ->
+ P = gp(),
+ p_cmd(P,?EFORMAT, [{string, lists:flatten(io_lib:format(Fmt,Args))}],void).
+
+
+%% install Fun/0 as a Fun to be invoked
+%% on signal Sig
+
+signal(Sig, Fun) ->
+ P = gp(),
+ put({signal_handler, Sig}, Fun),
+ p_cmd(P,?SIGNAL, [{int, Sig}], void).
+
+
+%%% screen management
+
+
+smg_fill_region (R, C, Nr, Nc, Ch) ->
+ P = gp(),
+ p_cmd(P,?SMG_FILL_REGION, [{int,R}, {int, C},
+ {int, Nr}, {int, Nc},
+ {char, Ch}], void).
+
+smg_set_char_set (A) ->
+ P = gp(),
+ p_cmd(P, ?SMG_SET_CHAR_SET, [{int, A}], void).
+
+smg_suspend_smg () ->
+ P = gp(),
+ p_cmd(P, ?SMG_SUSPEND_SMG, [], int).
+
+smg_resume_smg () ->
+ P = gp(),
+ p_cmd(P, ?SMG_RESUME_SMG, [], int).
+
+smg_erase_eol () ->
+ P = gp(),
+ p_cmd(P, ?SMG_ERASE_EOL, [], void).
+
+smg_gotorc (R, C) ->
+ P = gp(),
+ p_cmd(P, ?SMG_GOTORC, [{int, R}, {int, C}], void).
+
+smg_erase_eos () ->
+ P = gp(),
+ p_cmd(P, ?SMG_ERASE_EOS, [], void).
+
+smg_reverse_video () ->
+ P = gp(),
+ p_cmd(P, ?SMG_REVERSE_VIDEO, [], void).
+
+smg_set_color (C) ->
+ P = gp(),
+ p_cmd(P, ?SMG_SET_COLOR, [{int, C}], void).
+
+smg_normal_video () ->
+ P = gp(),
+ p_cmd(P, ?SMG_NORMAL_VIDEO, [], void).
+
+smg_printf (Format, Args) ->
+ P = gp(),
+ Str = io_lib:format(Format, Args),
+ p_cmd(P, ?SMG_WRITE_STRING, [{string, lists:flatten(Str)}], void).
+
+smg_vprintf () ->
+ exit(nyi).
+
+smg_write_string (Str) ->
+ P = gp(),
+ p_cmd(P, ?SMG_WRITE_STRING, [{string, Str}], void).
+
+smg_write_nstring (S, N) ->
+ L = lists:flatten(N),
+ Len = length(L),
+ if
+ Len < N ->
+ smg_write_string(L ++ lists:duplicate(N - Len, 32));
+ true ->
+ smg_write_string(L)
+ end.
+
+smg_write_char (Ch) ->
+ P = gp(),
+ p_cmd(P, ?SMG_WRITE_CHAR, [{char, Ch}], void).
+
+smg_write_nchars (S, N) ->
+ L = lists:sublist(lists:flatten(S), N),
+ smg_write_string(L).
+
+smg_write_wrapped_string (S, R, C, Nr, Nc, Fill) ->
+ P = gp(),
+ p_cmd(P, ?SMG_WRITE_WRAPPED_STRING, [{string, S},{int, R}, {int, C},
+ {int, Nr}, {int, Nc}, {int, Fill}],
+ void).
+
+smg_cls () ->
+ P = gp(),
+ p_cmd(P, ?SMG_CLS, [], void).
+
+smg_refresh () ->
+ P = gp(),
+ p_cmd(P, ?SMG_REFRESH, [], void).
+
+smg_touch_lines (R, Nr) ->
+ P = gp(),
+ p_cmd(P, ?SMG_TOUCH_LINES, [{int, R}, {int, Nr}], void).
+
+smg_touch_screen () ->
+ P = gp(),
+ p_cmd(P, ?SMG_TOUCH_SCREEN, [], void).
+
+smg_init_smg () ->
+ P = gp(),
+ p_cmd(P, ?SMG_INIT_SMG, [], int).
+
+smg_reinit_smg () ->
+ P = gp(),
+ p_cmd(P, ?SMG_REINIT_SMG, [], void).
+
+smg_reset_smg () ->
+ P = gp(),
+ p_cmd(P, ?SMG_RESET_SMG, [], void).
+
+smg_char_at () ->
+ P = gp(),
+ p_cmd(P, ?SMG_CHAR_AT, [], int).
+
+%% 0 == NULL
+smg_set_screen_start (R, C) ->
+ P = gp(),
+ p_cmd(P, ?SMG_SET_SCREEN_START, [{int, R}, {int, C}], int_int).
+
+smg_draw_hline (Len) ->
+ P = gp(),
+ p_cmd(P, ?SMG_DRAW_HLINE, [{int, Len}], void).
+
+smg_draw_vline (Len) ->
+ P = gp(),
+ p_cmd(P, ?SMG_DRAW_VLINE, [{int, Len}], void).
+
+smg_draw_object (R, C, Obj) ->
+ P = gp(),
+ p_cmd(P, ?SMG_DRAW_OBJECT, [{int, R}, {int, C}, {int, Obj}], void).
+
+smg_draw_box (R, C, Dr, Dc) ->
+ P = gp(),
+ p_cmd(P, ?SMG_DRAW_BOX, [], void).
+
+smg_get_column () ->
+ P = gp(),
+ p_cmd(P, ?SMG_GET_COLUMN, [], int).
+
+smg_get_row () ->
+ P = gp(),
+ p_cmd(P, ?SMG_GET_RO, [], int).
+
+smg_forward (N) ->
+ P = gp(),
+ p_cmd(P, ?SMG_FORWARD, [{int, N}], void).
+
+smg_write_color_chars (S, Len) ->
+ P = gp(),
+ p_cmd(P, ?SMG_WRITE_COLOR_CHARS, [{smg_char_type, S}, {int, Len}], void).
+
+smg_read_raw (Len) ->
+ P = gp(),
+ p_cmd(P, ?SMG_READ_RAW, [{int, Len}], smg_char_type).
+
+smg_write_raw (Str, Len) ->
+ P = gp(),
+ p_cmd(P, ?SMG_WRITE_RAW, [{smg_char_type, Str}, {int, Len}], int).
+
+smg_set_color_in_region (Color, R, C, Dr, Dc) ->
+ P = gp(),
+ p_cmd(P, ?SMG_SET_COLOR_IN_REGION, [{int, Color}, {int, R}, {int, C},
+ {int, Dr}, {int, Dc}], void).
+
+
+
+
+
+%%%%%%% auxilliary functions %%%%%%%%%%%%%%%%%
+
+
+encode_var(baud_rate) -> 1;
+encode_var(read_fd) -> 2;
+encode_var(abort_char) -> 3;
+encode_var(ignore_user_abort) -> 4;
+encode_var(input_buffer_len) -> 5;
+encode_var(keyboard_quit) -> 6;
+encode_var(last_key_char) -> 7;
+encode_var(rl_eof_char) -> 8;
+encode_var(rline_quit) -> 9;
+encode_var(screen_rows) -> 10;
+encode_var(screen_cols) -> 11;
+encode_var(tab_width) -> 12;
+encode_var(newline_behaviour) -> 13;
+encode_var(error) -> 14;
+encode_var(version) -> 15;
+encode_var(backspace_moves) -> 16;
+encode_var(display_eight_bit) -> 17.
+
+
+
+p_cmd(P, Op, ArgList, void) ->
+ Cmd = [Op | mk_args(ArgList)],
+ %?Debug("CMD ~p~n", [Cmd]),
+ P ! {self(), {command, Cmd}};
+
+
+p_cmd(P, Op, ArgList, Expect) ->
+ Cmd = [Op | mk_args(ArgList)],
+ P ! {self(), {command, Cmd}},
+ case rec_loop(P, Expect, nosig) of
+ {Reply, nosig} ->
+ Reply;
+ {Reply, SignalFun} ->
+ SignalFun(),
+ Reply
+ end.
+
+rec_loop(P, Expect, Sig) ->
+ receive
+ {P, {data, [1 |What]}} ->
+ {expect(What, Expect), Sig};
+ {P, {data, [0 , X1, X2, X3, X4]}} ->
+ SigNo = ?i32(X1,X2, X3, X4),
+ case get({signal_handler, SigNo}) of
+ undefined ->
+ rec_loop(P, Expect, Sig);
+ Fun ->
+ rec_loop(P, Expect, Fun)
+ end;
+ {'EXIT', P, Reason} ->
+ exit(Reason)
+ after 200 ->
+ P ! {self(), {command, [255]}}, % tick
+ rec_loop(P, Expect, Sig)
+ end.
+
+
+expect(List, smg_char_type) ->
+ upack_smg_char_type(List);
+expect([X1,X2, X3, X4], int32) ->
+ ?i32(X1,X2, X3, X4);
+expect([X1,X2, X3, X4], int) ->
+ ?i32(X1,X2, X3, X4);
+expect([X1,X2, X3, X4, Y1, Y2, Y3, Y4], int_int) ->
+ {?i32(X1,X2, X3, X4), ?i32(Y1, Y2, Y3, Y4)};
+
+expect(List, string) ->
+ List.
+
+
+upack_smg_char_type([X1, X2 |Tail]) ->
+ [?u16(X1, X2) | upack_smg_char_type(Tail)];
+upack_smg_char_type([]) ->
+ [];
+upack_smg_char_type([X]) ->
+ [X].
+
+
+mk_args([]) ->
+ [];
+mk_args([{int, Int} |Tail]) when integer(Int) ->
+ [?int32(Int) | mk_args(Tail)];
+mk_args([{char, Char} |Tail]) when integer(Char) ->
+ [Char| mk_args(Tail)];
+mk_args([{string, Str} |Tail]) when list(Str) ->
+ [Str, 0 | mk_args(Tail)];
+mk_args([{string, Str} |Tail]) when atom(Str) ->
+ [atom_to_list(Str), 0 | mk_args(Tail)];
+mk_args([{smg_char_type, Str} |Tail]) when list(Str) ->
+ Len = 2 * length(Str),
+ List = [?int32(Len) | lists:map(fun(I) -> ?int16(I) end, Str)] ,
+ [List| mk_args(Tail)].
+
+
+open_slang_driver() ->
+ erl_ddll:start(),
+ Path=case code:priv_dir(slang) of
+ {error, _} ->
+ {ok, Dir, _} = regexp:sub(code:which(slang),
+ "ebin/slang.beam",[]),
+ Dir ++ "/priv";
+ Dir ->
+ Dir
+ end,
+ case erl_ddll:load_driver(Path, "slang_drv") of
+ ok ->
+ ok;
+ {error,{already_started, _}} ->
+ ok;
+ {error, What} ->
+ error_logger:format("Failed to open driver ~p~n", [What]),
+ exit(nodriver)
+ end,
+ P = open_port({spawn, slang_drv}, []),
+ P.
+
+
+gp() ->
+ case get(slang_port) of
+ undefined ->
+ Port = open_slang_driver(),
+ put(slang_port, Port),
+ Port;
+ Port ->
+ Port
+ end.
+
+
+%% all the not so necessary tt_ functions
+%% int
+tt_flush_output() ->
+ P = gp(),
+ p_cmd(P, ?TT_FLUSH_OUTPUT, [], int).
+
+%% void
+tt_set_scroll_region(X,Y) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_SCROLL_REGION, [{int, X}, {int, Y}], void).
+
+% void
+tt_reset_scroll_region() ->
+ P = gp(),
+ p_cmd(P, ?TT_RESET_SCROLL_REGION,[],void).
+
+tt_reverse_video(Int) ->
+ P = gp(),
+ p_cmd(P, ?TT_REVERSE_VIDEO,[{int, Int}],void).
+
+tt_bold_video() ->
+ P = gp(),
+ p_cmd(P, ?TT_BOLD_VIDEO,[],void).
+
+tt_begin_insert() ->
+ P = gp(),
+ p_cmd(P, ?TT_BEGIN_INSERT,[],void).
+
+tt_end_insert() ->
+ P = gp(),
+ p_cmd(P, ?TT_END_INSERT,[],void).
+
+tt_del_eol() ->
+ P = gp(),
+ p_cmd(P, ?TT_DEL_EOL,[],void).
+
+tt_goto_rc() ->
+ P = gp(),
+ p_cmd(P, ?TT_GOTO_RC,[],void).
+
+tt_delete_nlines(Int) ->
+ P = gp(),
+ p_cmd(P, ?TT_DELETE_NLINES,[{int, Int}],void).
+
+tt_delete_char() ->
+ P = gp(),
+ p_cmd(P, ?TT_DELETE_CHAR,[],void).
+
+tt_erase_line() ->
+ P = gp(),
+ p_cmd(P, ?TT_ERASE_LINE,[],void).
+
+tt_normal_video() ->
+ P = gp(),
+ p_cmd(P, ?TT_NORMAL_VIDEO,[],void).
+
+tt_cls() ->
+ P = gp(),
+ p_cmd(P, ?TT_CLS,[],void).
+
+tt_beep() ->
+ P = gp(),
+ p_cmd(P, ?TT_BEEP,[],void).
+
+tt_reverse_index(Int) ->
+ P = gp(),
+ p_cmd(P, ?TT_REVERSE_INDEX,[{int, Int}],void).
+
+tt_smart_puts(S1, S2, X, Y) ->
+ P = gp(),
+ p_cmd(P, ?TT_SMART_PUTS,[{smg_char_type, S1}, {smg_char_type, S2},
+ {int, X}, {int, Y}],void).
+
+tt_write_string(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_WRITE_STRING,[{string, Str}],void).
+
+tt_putchar(Char) ->
+ P = gp(),
+ p_cmd(P, ?TT_PUTCHAR,[{int, Char}],void).
+
+tt_init_video() ->
+ P = gp(),
+ p_cmd(P, ?TT_INIT_VIDEO,[],int).
+
+tt_reset_video() ->
+ P = gp(),
+ p_cmd(P, ?TT_RESET_VIDEO,[],void).
+
+tt_get_terminfo() ->
+ P = gp(),
+ p_cmd(P, ?TT_GET_TERMINFO,[],void).
+
+tt_get_screen_size() ->
+ P = gp(),
+ p_cmd(P, ?TT_GET_SCREEN_SIZE,[],void).
+
+tt_set_cursor_visibility(Int) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_CURSOR_VISIBILITY,[{int, Int}],int).
+
+tt_set_mouse_mode(X, Y) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_MOUSE_MODE,[{int, X}, {int, Y}],int).
+
+tt_initialize(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_INITIALIZE,[{string, Str}],int).
+
+
+tt_enable_cursor_keys() ->
+ P = gp(),
+ p_cmd(P, ?TT_ENABLE_CURSOR_KEYS,[],void).
+
+tt_set_term_vtxxx() ->
+ exit(nyi),
+ P = gp(),
+ p_cmd(P, ?TT_SET_TERM_VTXXX,[],void).
+
+tt_set_color_esc(Int, Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_COLOR_ESC,[{int, Int}, {string, Str}],void).
+
+tt_wide_width() ->
+ P = gp(),
+ p_cmd(P, ?TT_WIDE_WIDTH,[],void).
+
+tt_narrow_width() ->
+ P = gp(),
+ p_cmd(P, ?TT_NARROW_WIDTH,[],void).
+
+tt_set_alt_char_set() ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_ALT_CHAR_SET,[],void).
+
+tt_write_to_status_line(Int, Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_WRITE_TO_STATUS_LINE,[{int, Int}, {string, Str}],void).
+
+tt_disable_status_line() ->
+ P = gp(),
+ p_cmd(P, ?TT_DISABLE_STATUS_LINE,[],void).
+
+tt_tgetstr(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_TGETSTR,[{string, Str}],string).
+
+tt_tgetnum(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_TGETNUM,[{string, Str}],int).
+
+tt_tgetflag(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_TGETFLAG,[{string, Str}],int).
+
+tt_tigetent(Str) ->
+ P = gp(),
+ p_cmd(P, ?TT_TIGETENT,[{string, Str}],string).
+
+
+tt_tigetstr() ->
+ exit(nyi),
+ P = gp(),
+ p_cmd(P, ?TT_TIGETSTR,[],void).
+
+tt_tigetnum() ->
+ exit(nyi),
+ P = gp(),
+ p_cmd(P, ?TT_TIGETNUM,[],void).
+
+sltt_get_color_object(Int) ->
+ P = gp(),
+ p_cmd(P, ?SLTT_GET_COLOR_OBJECT,[{int, Int}], int).
+
+tt_set_color_object(Int, CType) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_COLOR_OBJECT,[{int, Int}, {int, CType}],void).
+
+tt_set_color(Obj, Name, Fg, Bg) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_COLOR,[{int, Obj}, {string, Name},
+ {string, Fg}, {string, Bg}],void).
+
+tt_set_mono(Int, Str, Attr) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_MONO,[{int, Int}, {string, Str},
+ {int, Attr}],void).
+
+tt_add_color_attribute(Int, Ctype) ->
+ P = gp(),
+ p_cmd(P, ?TT_ADD_COLOR_ATTRIBUTE,[{int, Int}, {int, Ctype}],void).
+
+tt_set_color_fgbg(Int, CT1, CT2) ->
+ P = gp(),
+ p_cmd(P, ?TT_SET_COLOR_FGBG,[{int, Int}, {int, CT1}, {int, CT2}],void).
+
+
+
+%% debug slang apps by tail -f 'ing /tmp/slang.debug
+%% use ?DEBUG(F, A) or slang:debug/2,
+
+debug(File, Line, Fmt, Args) ->
+ DFD = case get(slang_debug_fd) of
+ undefined ->
+ case file:open("/tmp/slang.debug", [append]) of
+ {ok, Fd} ->
+ put(slang_debug_fd, Fd),
+ Fd;
+ Err ->
+ exit({nodebugfd, Err})
+ end;
+ Fd ->
+ Fd
+ end,
+
+ Str = lists:flatten(
+ io_lib:format("DEBUG ~s:~p, pid ~w: ~n",
+ [filename:basename(File),
+ Line, self()])),
+
+ case io:format(DFD, Str ++ Fmt ++ "~n", Args) of
+ ok -> ok;
+ _ -> io:format(DFD, "ERROR ~p:~p: Pid ~w: (bad format)~n~p,~p~n",
+ [File, Line, self(), Fmt, Args]),
+
+ ok
+ end.
+