PageRenderTime 31ms CodeModel.GetById 9ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/deps/iconv/src/iconv.erl

https://code.google.com/p/zotonic/
Erlang | 218 lines | 128 code | 33 blank | 57 comment | 0 complexity | f146395dc9826630bf8aa99997d704b3 MD5 | raw file
  1-module(iconv).
  2%%%----------------------------------------------------------------------
  3%%% File    : iconv.erl
  4%%% Author  : Torbjorn Tornkvist <tobbe@bluetail.com>
  5%%% Purpose : iconv support
  6%%% Created : 23 Mar 2004 by <tobbe@bluetail.com>
  7%%%
  8%%% $Id$
  9%%%----------------------------------------------------------------------
 10-behaviour(gen_server).
 11-export([start/0, start_link/0, stop/0, open/2, conv/2, close/1]).
 12
 13%% gen_server callbacks
 14-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 
 15	 terminate/2, code_change/3]).
 16
 17-record(state, {port}).
 18
 19-ifdef(TEST).
 20-include_lib("eunit/include/eunit.hrl").
 21-endif.
 22
 23%%% op codes
 24-define(IV_OPEN,    $o).
 25-define(IV_CONV,    $v).
 26-define(IV_CLOSE,   $c).
 27
 28-define(INBUF_SZ, 512).
 29
 30-define(DRV_NAME, "iconv_drv").
 31-define(SERVER, ?MODULE).
 32
 33%%%----------------------------------------------------------------------
 34%%% API
 35%%%----------------------------------------------------------------------
 36start() ->
 37    gen_server:start({local, ?SERVER}, ?MODULE, [], []).
 38
 39start_link() ->
 40    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
 41
 42stop() ->
 43	gen_server:call(?SERVER, stop).
 44
 45%%open(To, From) -> {ok, ballen};
 46open(To, From) ->
 47    gen_server:call(?SERVER, {open, l2b(To), l2b(From)}, infinity).
 48
 49%%conv(Cd, String) -> {ok, l2b(String)};
 50conv(Cd, String) when is_binary(Cd) ->
 51    gen_server:call(?SERVER, {conv, Cd, l2b(String)}, infinity).
 52
 53%%close(Cd) -> ok;
 54close(Cd) when is_binary(Cd) ->
 55    gen_server:call(?SERVER, {close, Cd}, infinity).
 56
 57%%%----------------------------------------------------------------------
 58%%% Callback functions from gen_server
 59%%%----------------------------------------------------------------------
 60
 61%%----------------------------------------------------------------------
 62%% Func: init/1
 63%% Returns: {ok, State}          |
 64%%          {ok, State, Timeout} |
 65%%          ignore               |
 66%%          {stop, Reason}
 67%%----------------------------------------------------------------------
 68init([]) ->
 69    erl_ddll:start(),
 70    Path = case code:priv_dir(iconv) of
 71			{error, _} ->
 72				case load_path(?DRV_NAME++".so") of
 73					{error, _} ->
 74						error;
 75					{ok, P} ->
 76						P
 77				end;
 78			P ->
 79				P
 80		end,
 81
 82		case Path of
 83			error ->
 84				{stop, no_driver};
 85			Path ->
 86				case erl_ddll:load_driver(Path, ?DRV_NAME) of
 87					ok ->
 88						Port = open_port({spawn, ?DRV_NAME}, [binary]),
 89						{ok, #state{port = Port}};
 90					{error, Error} ->
 91						error_logger:format("Error loading driver: " ++ erl_ddll:format_error(Error), []),
 92						{stop, bad_driver}
 93				end
 94		end.
 95
 96%%----------------------------------------------------------------------
 97%% Func: handle_call/3
 98%% Returns: {reply, Reply, State}          |
 99%%          {reply, Reply, State, Timeout} |
100%%          {noreply, State}               |
101%%          {noreply, State, Timeout}      |
102%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
103%%          {stop, Reason, State}            (terminate/2 is called)
104%%----------------------------------------------------------------------
105handle_call({open, To, From}, _, S) ->
106    ToLen   = byte_size(To),
107    FromLen = byte_size(From),
108    Msg = <<?IV_OPEN,ToLen:16,To/binary,FromLen:16,From/binary>>,
109    Reply = call_drv(S#state.port, Msg),
110    {reply, Reply, S};
111%%
112handle_call({conv, Cd, Buf}, _, S) ->
113    CdLen  = byte_size(Cd),
114    BufLen = byte_size(Buf),
115    Msg = <<?IV_CONV,CdLen:16,Cd/binary,BufLen:16,Buf/binary>>,
116    Reply = call_drv(S#state.port, Msg),
117    {reply, Reply, S};
118
119%%
120handle_call({close, Cd}, _, S) ->
121    CdLen  = byte_size(Cd),
122    Msg = <<?IV_CLOSE,CdLen:16,Cd/binary>>,
123    Reply = call_drv(S#state.port, Msg),
124    {reply, Reply, S};
125
126handle_call(stop, _, S) ->
127	{stop, normal, ok,  S}.
128
129call_drv(Port, Msg) ->
130    erlang:port_command(Port, [Msg]),
131    recv(Port).
132
133recv(Port) ->
134    receive
135	{Port, ok} ->
136	    ok;
137	{Port, value, Bin} ->
138	    {ok,Bin};
139	{Port, error, ErrAtom} ->
140	    {error, ErrAtom}
141    end.
142
143
144
145%%----------------------------------------------------------------------
146%% Func: handle_cast/2
147%% Returns: {noreply, State}          |
148%%          {noreply, State, Timeout} |
149%%          {stop, Reason, State}            (terminate/2 is called)
150%%----------------------------------------------------------------------
151handle_cast(_Msg, State) ->
152    {noreply, State}.
153
154%%----------------------------------------------------------------------
155%% Func: handle_info/2
156%% Returns: {noreply, State}          |
157%%          {noreply, State, Timeout} |
158%%          {stop, Reason, State}            (terminate/2 is called)
159%%----------------------------------------------------------------------
160handle_info(_Info, State) ->
161    {noreply, State}.
162
163%%----------------------------------------------------------------------
164%% Func: terminate/2
165%% Purpose: Shutdown the server
166%% Returns: any (ignored by gen_server)
167%%----------------------------------------------------------------------
168terminate(_Reason, _State) ->
169    ok.
170
171
172code_change(_, _, _) ->
173    ok.
174
175%%%----------------------------------------------------------------------
176%%% Internal functions
177%%%----------------------------------------------------------------------
178load_path(File) ->
179	case lists:zf(fun(Ebin) ->
180					Priv = Ebin ++ "/../priv/",
181					case file:read_file_info(Priv ++ File) of
182						{ok, _} -> {true, Priv};
183						_ -> false
184					end
185			end, code:get_path()) of
186		[Dir|_] ->
187			{ok, Dir};
188		[] ->
189			error_logger:format("Error: ~s not found in code path\n", [File]),
190			{error, enoent}
191	end.
192
193l2b(L) when is_list(L)   -> list_to_binary(L);
194l2b(B) when is_binary(B) -> B.
195
196-ifdef(TEST).
197
198smtp_session_test_() ->
199	{setup,
200		fun() ->
201				iconv:start()
202		end,
203		fun(_) ->
204				iconv:stop()
205		end,
206		[
207			{"Convert from latin-1 to utf-8",
208				fun() ->
209						{ok, CD} = iconv:open("utf-8", "ISO-8859-1"),
210						?assertEqual({ok, <<"hello world">>}, iconv:conv(CD, "hello world")),
211						iconv:close(CD)
212				end
213			}
214		]
215	}.
216
217
218			-endif.