PageRenderTime 38ms CodeModel.GetById 11ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/deps/gen_smtp/src/binstr.erl

https://code.google.com/p/zotonic/
Erlang | 329 lines | 257 code | 41 blank | 31 comment | 4 complexity | 6ad34b2526b8e43d8a497b28f6762bff MD5 | raw file
  1%%% Copyright 2009 Andrew Thompson <andrew@hijacked.us>. All rights reserved.
  2%%%
  3%%% Redistribution and use in source and binary forms, with or without
  4%%% modification, are permitted provided that the following conditions are met:
  5%%%
  6%%%   1. Redistributions of source code must retain the above copyright notice,
  7%%%      this list of conditions and the following disclaimer.
  8%%%   2. Redistributions in binary form must reproduce the above copyright
  9%%%      notice, this list of conditions and the following disclaimer in the
 10%%%      documentation and/or other materials provided with the distribution.
 11%%%
 12%%% THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR
 13%%% IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 14%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 15%%% EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 16%%% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 17%%% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 18%%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 19%%% ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 20%%% (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 21%%% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 22
 23%% @doc Some functions for working with binary strings.
 24
 25-module(binstr).
 26
 27-export([
 28		strchr/2,
 29		strrchr/2,
 30		strpos/2,
 31		strrpos/2,
 32		substr/2,
 33		substr/3,
 34		split/3,
 35		split/2,
 36		chomp/1,
 37		strip/1,
 38		strip/2,
 39		strip/3,
 40		to_lower/1,
 41		to_upper/1,
 42		all/2,
 43		reverse/1,
 44		reverse_str_to_bin/1,
 45		join/2
 46]).
 47
 48-spec strchr(Bin :: binary(), C :: char()) -> non_neg_integer().
 49strchr(Bin, C) when is_binary(Bin) ->
 50	% try to use the R14B binary module
 51	try binary:match(Bin, <<C>>) of
 52		{Index, _Length} ->
 53			Index + 1;
 54		nomatch ->
 55			0
 56	catch
 57		_:_ ->
 58			strchr(Bin, C, 0)
 59	end.
 60
 61strchr(Bin, C, I) ->
 62	case Bin of
 63		<<_X:I/binary>> ->
 64			0;
 65		<<_X:I/binary, C, _Rest/binary>> ->
 66			I+1;
 67		_ ->
 68			strchr(Bin, C, I+1)
 69	end.
 70
 71
 72-spec strrchr(Bin :: binary(), C :: char()) -> non_neg_integer().
 73strrchr(Bin, C) ->
 74	strrchr(Bin, C, byte_size(Bin)).
 75
 76strrchr(Bin, C, I) ->
 77	case Bin of
 78		<<_X:I/binary, C, _Rest/binary>> ->
 79			I+1;
 80		_ when I =< 1 ->
 81			0;
 82		_ ->
 83			strrchr(Bin, C, I-1)
 84	end.
 85
 86
 87-spec strpos(Bin :: binary(), C :: binary() | list()) -> non_neg_integer().
 88strpos(Bin, C) when is_binary(Bin), is_list(C) ->
 89	strpos(Bin, list_to_binary(C));
 90strpos(Bin, C) when is_binary(Bin) ->
 91	% try to use the R14B binary module
 92	try binary:match(Bin, C) of
 93			{Index, _Length} ->
 94				Index+1;
 95			nomatch ->
 96				0
 97	catch
 98		_:_ ->
 99			strpos(Bin, C, 0, byte_size(C))
100	end.
101
102
103strpos(Bin, C, I, S) ->
104	case Bin of
105		<<_X:I/binary>> ->
106			0;
107		<<_X:I/binary, C:S/binary, _Rest/binary>> ->
108			I+1;
109		_ ->
110			strpos(Bin, C, I+1, S)
111	end.
112
113
114-spec strrpos(Bin :: binary(), C :: binary() | list()) -> non_neg_integer().
115strrpos(Bin, C) ->
116	strrpos(Bin, C, byte_size(Bin), byte_size(C)).
117
118strrpos(Bin, C, I, S) ->
119	case Bin of
120		<<_X:I/binary, C:S/binary, _Rest/binary>> ->
121			I+1;
122		_ when I =< 1 ->
123			0;
124		_ ->
125			strrpos(Bin, C, I-1, S)
126	end.
127
128
129-spec substr(Bin :: binary(), Start :: pos_integer() | neg_integer()) -> binary().
130substr(<<>>, _) ->
131	<<>>;
132substr(Bin, Start) when Start > 0 ->
133	{_, B2} = split_binary(Bin, Start-1),
134	B2;
135substr(Bin, Start) when Start < 0 ->
136	Size = byte_size(Bin),
137	{_, B2} = split_binary(Bin, Size+Start),
138	B2.
139
140
141-spec substr(Bin :: binary(), Start :: pos_integer() | neg_integer(), Length :: pos_integer()) -> binary().
142substr(<<>>, _, _) ->
143	<<>>;
144substr(Bin, Start, Length) when Start > 0 ->
145	{_, B2} = split_binary(Bin, Start-1),
146	{B3, _} = split_binary(B2, Length),
147	B3;
148substr(Bin, Start, Length) when Start < 0 ->
149	Size = byte_size(Bin),
150	{_, B2} = split_binary(Bin, Size+Start),
151	{B3, _} = split_binary(B2, Length),
152	B3.
153
154
155-spec split(Bin :: binary(), Separator :: binary(), SplitCount :: pos_integer()) -> [binary()].
156split(Bin, Separator, SplitCount) ->
157	split_(Bin, Separator, SplitCount, []).
158
159split_(<<>>, _Separator, _SplitCount, Acc) ->
160	lists:reverse(Acc);
161split_(Bin, <<>>, 1, Acc) ->
162	lists:reverse([Bin | Acc]);
163split_(Bin, _Separator, 1, Acc) ->
164	lists:reverse([Bin | Acc]);
165split_(Bin, <<>>, SplitCount, Acc) ->
166	split_(substr(Bin, 2), <<>>, SplitCount - 1, [substr(Bin, 1, 1) | Acc]);
167split_(Bin, Separator, SplitCount, Acc) ->
168	case strpos(Bin, Separator) of
169		0 ->
170			lists:reverse([Bin | Acc]);
171		Index ->
172			Head = substr(Bin, 1, Index - 1),
173			Tailpresplit = substr(Bin, Index + byte_size(Separator)),
174			split_(Tailpresplit, Separator, SplitCount - 1, [Head | Acc])
175	end.
176
177
178-spec split(Bin :: binary(), Separator :: binary()) -> [binary()].
179split(Bin, Separator) ->
180	% try to use the R14B binary module
181	try binary:split(Bin, Separator, [global]) of
182		Result ->
183			case lists:last(Result) of
184				<<>> ->
185					lists:sublist(Result, length(Result) - 1);
186				_ ->
187					Result
188			end
189	catch
190		_:_ ->
191			split_(Bin, Separator, [])
192	end.
193
194split_(<<>>, _Separator, Acc) ->
195	lists:reverse(Acc);
196split_(Bin, <<>>, Acc) ->
197	split_(substr(Bin, 2), <<>>, [substr(Bin, 1, 1) | Acc]);
198split_(Bin, Separator, Acc) ->
199	case strpos(Bin, Separator) of
200		0 ->
201			lists:reverse([Bin | Acc]);
202		Index ->
203			split_(substr(Bin, Index + byte_size(Separator)), Separator, [substr(Bin, 1, Index - 1) | Acc])
204	end.
205
206
207-spec chomp(Bin :: binary()) -> binary().
208chomp(Bin) ->
209	L = byte_size(Bin),
210	try [binary:at(Bin, L-2), binary:at(Bin, L-1)] of
211		"\r\n" ->
212			binary:part(Bin, 0, L-2);
213		[_, X] when X == $\r; X == $\n ->
214			binary:part(Bin, 0, L-1);
215		_ ->
216			Bin
217	catch
218		_:_ ->
219			io:format("fallback, yay~n"),
220			L2 = L - 1,
221			case strrpos(Bin, <<"\r\n">>) of
222				L2 ->
223					substr(Bin, 1,  L2 - 1);
224				_ ->
225					case strrchr(Bin, $\n) of
226						L ->
227							substr(Bin, 1, L - 1);
228						_ ->
229							case strrchr(Bin, $\r) of
230								L ->
231									substr(Bin, 1, L - 1);
232								_ ->
233									Bin
234							end
235					end
236			end
237	end.
238
239
240-spec strip(Bin :: binary()) -> binary().
241strip(Bin) ->
242	strip(Bin, both, $\s).
243
244-spec strip(Bin :: binary(), Dir :: 'left' | 'right' | 'both') -> binary().
245strip(Bin, Dir) ->
246	strip(Bin, Dir, $\s).
247
248-spec strip(Bin :: binary(), Dir :: 'left' | 'right' | 'both', C :: non_neg_integer()) -> binary().
249strip(<<>>, _, _) ->
250	<<>>;
251strip(Bin, both, C) ->
252	strip(strip(Bin, left, C), right, C);
253strip(<<C, _Rest/binary>> = Bin, left, C) ->
254	strip(substr(Bin, 2), left, C);
255strip(Bin, left, _C) ->
256	Bin;
257strip(Bin, right, C) ->
258	L = byte_size(Bin),
259	try binary:at(Bin, L-1) of
260		C ->
261			strip(binary:part(Bin, 0, L-1), right, C);
262		_ ->
263			Bin
264	catch
265		_:_ ->
266			case strrchr(Bin, C) of
267				L ->
268					strip(substr(Bin, 1, L - 1), right, C);
269				_ ->
270					Bin
271			end
272	end.
273
274-spec to_lower(Bin :: binary()) -> binary().
275to_lower(Bin) ->
276	to_lower(Bin, <<>>).
277
278to_lower(<<>>, Acc) ->
279	Acc;
280to_lower(<<H, T/binary>>, Acc) when H >= $A, H =< $Z ->
281	H2 = H + 32,
282	to_lower(T, <<Acc/binary, H2>>);
283to_lower(<<H, T/binary>>, Acc) ->
284	to_lower(T, <<Acc/binary, H>>).
285
286
287-spec to_upper(Bin :: binary()) -> binary().
288to_upper(Bin) ->
289	to_upper(Bin, <<>>).
290
291to_upper(<<>>, Acc) ->
292	Acc;
293to_upper(<<H, T/binary>>, Acc) when H >= $a, H =< $z ->
294	H2 = H - 32,
295	to_upper(T, <<Acc/binary, H2>>);
296to_upper(<<H, T/binary>>, Acc) ->
297	to_upper(T, <<Acc/binary, H>>).
298
299-spec all(Fun :: function(), Binary :: binary()) -> boolean().
300all(_Fun, <<>>) ->
301	true;
302all(Fun, Binary) ->
303	Res = << <<X/integer>> || <<X>> <= Binary, Fun(X) >>,
304	Binary == Res.
305%all(Fun, <<H, Tail/binary>>) ->
306%	Fun(H) =:= true andalso all(Fun, Tail).
307
308%% this is a cool hack to very quickly reverse a binary
309-spec reverse(Bin :: binary()) -> binary().
310reverse(Bin) ->
311	Size = byte_size(Bin)*8,
312	<<T:Size/integer-little>> = Bin,
313	<<T:Size/integer-big>>.
314
315%% reverse a string into a binary - can be faster than lists:reverse on large
316%% lists, even if you run binary_to_string on the result. For smaller strings
317%% it's probably slower (but still not that bad).
318-spec reverse_str_to_bin(String :: string()) -> binary().
319reverse_str_to_bin(String) ->
320	reverse(list_to_binary(String)).
321
322-spec join(Binaries :: [binary()|list()], Glue :: binary() | list()) -> binary().
323join(Binaries, Glue) ->
324	join(Binaries, Glue, []).
325
326join([H], _Glue, Acc) ->
327	list_to_binary(lists:reverse([H | Acc]));
328join([H|T], Glue, Acc) ->
329	join(T, Glue, [Glue, H | Acc]).