%%% BEGIN openflax/string.erl %%% %%% %%% openflax - Open Source web server for Erlang/OTP %%% Copyright (c)2004 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 OpenFlax string functions. %% %%

These are functions for manipulating strings used by OpenFlax. %% They should only be used by OpenFlax; for general-purpose versions %% of these functions, see the ce_string, ce_lists %% and ce_lib modules of the ce application.

%% %% @end -module(openflax.string). -vsn('$Id: string.erl 31 2004-04-23 07:00:11Z catseye $'). -author('catseye@catseye.mb.ca'). -copyright('Copyright (c)2004 Cat`s Eye Technologies. All rights reserved.'). -export([to_lower/1, to_upper/1, to_caps/1]). -export([truncate/1, chomp/1]). -export([join/2, keyvalue/2, substitute/3]). -export([to_header/1, from_header/1]). -export([from_term/1, to_atom/1]). -export([decode_hex/1]). -export([from_datetime_rfc_1123/0, from_datetime_rfc_1123/1]). % module imports -import(lists). -import(string). -import(io_lib). -import(calendar). %% @spec to_upper(string()) -> string() %% @doc Converts the given string to all uppercase. to_upper(String) -> to_upper(lists:flatten(String), []). to_upper([C | Cs], Acc) when C >= $a, C =< $z -> to_upper(Cs, [C - ($a - $A) | Acc]); to_upper([C | Cs], Acc) -> to_upper(Cs, [C | Acc]); to_upper([], Acc) -> lists:reverse(Acc). %% @spec to_lower(string()) -> string() %% @doc Converts the given string to all lowercase. to_lower(String) -> to_lower(lists:flatten(String), []). to_lower([C | Cs], Acc) when C >= $A, C =< $Z -> to_lower(Cs, [C + ($a - $A) | Acc]); to_lower([C | Cs], Acc) -> to_lower(Cs, [C | Acc]); to_lower([], Acc) -> lists:reverse(Acc). %% @spec to_caps(string() | atom()) -> string() %% @doc Capitalizes each letter that is not preceded by a letter. to_caps(S) -> to_caps(S, $ , $ ). to_caps(S, From, To) when atom(S) -> to_caps(atom_to_list(S), From, To); to_caps(S, From, To) when list(S) -> to_caps(S, From, To, [], $ ). to_caps([], _From, _To, Acc, _Last) -> lists:flatten(lists:reverse(Acc)); to_caps([From | T], From, To, Acc, _Last) -> to_caps(T, From, To, [To | Acc], To); to_caps([H | T], From, To, Acc, Last) when Last >= $a, Last =< $z; Last >= $A, Last =< $Z -> to_caps(T, From, To, [to_lower([H]) | Acc], H); to_caps([H | T], From, To, Acc, _Last) -> to_caps(T, From, To, [to_upper([H]) | Acc], H). %% @spec truncate(string()) -> string() %% @doc Returns a string containing all but the last character %% of a given string. truncate([]) -> []; truncate([_]) -> []; truncate([X, _]) -> [X]; truncate([H | T]) -> [H] ++ truncate(T). %% @spec chomp(string()) -> string() %% @doc Removes all newlines from the end of a string. %% Should work on both 'nix and MS-DOS newlines. chomp([]) -> []; chomp(List) when list(List) -> lists:reverse(chomp0(lists:reverse(List))). chomp0([]) -> []; chomp0([H | T]) when H == 10; H == 13 -> chomp0(T); chomp0(L) -> L. %% @spec join(string(), [string()]) -> string() %% @doc Joins strings with a delimeter between each part. join(P, L) -> join0(P, L, []). join0(_P, [], O) -> O; join0(_P, [X], O) -> O ++ X; join0(P, [X | T], O) -> join0(P, T, O ++ X ++ P). %% @spec keyvalue(string(), string()) -> {string(), string()} %% @doc Gets the key and value from a line of text. %% Can be used to parse simple mail headers, http headers, etc. keyvalue(String, Delim) -> case string:tokens(String, Delim) of [Key | Data] -> Data0 = join(Delim, Data), Data1 = string:strip(Data0, both), Key0 = string:strip(Key, both), {Key0, Data1}; [] -> {"", ""} end. %% @spec substitute(char(), char(), string()) -> string() %% @doc Returns a string with the all characters equal to the first argument %% replaced with the second argument. substitute(A, B, L) -> substitute(A, B, L, []). substitute(_A, _B, [], Acc) -> lists:reverse(Acc); substitute(A, B, [A | T], Acc) -> substitute(A, B, T, [B | Acc]); substitute(A, B, [H | T], Acc) -> substitute(A, B, T, [H | Acc]). %% @spec from_header(string()) -> string() %% @doc Given an HTTP-header format string such as "Content-Type", returns %% a string suitable for easy use as an atom (content_type.) from_header(String) -> substitute($-, $_, to_lower(String)). %% @spec to_header(string()) -> string() %% @doc Given an string such as "content_type", returns a string suitable %% for use as an HTTP-header field name ("Content-Type".) to_header(String) -> substitute($_, $-, to_caps(String)). %% @spec from_term(term()) -> string() %% @doc Tries to convert any term into a string. from_term(F) when is_float(F) -> float_to_list(F); from_term(I) when is_integer(I) -> integer_to_list(I); from_term(A) when is_atom(A) -> atom_to_list(A); from_term(S) when is_list(S) -> S; from_term(X) -> io_lib:format("~w", [X]). %% @spec to_atom(string()) -> atom() %% @doc Tries to convert a string into an atom. to_atom(String) -> list_to_atom(lists:flatten(String)). %% @spec decode_hex(string()) -> integer() %% @doc Parses the given string as an integer in hexadecimal notation. decode_hex(String) -> decode_hex(String, 0). decode_hex([], Acc) -> Acc; decode_hex([Head | Tail], Acc) -> decode_hex(Tail, Acc * 16 + decode_hex_char(Head)). decode_hex_char(Digit) when Digit >= $0, Digit =< $9 -> Digit - $0; decode_hex_char(Digit) when Digit >= $a, Digit =< $z -> (Digit - $a) + 10; decode_hex_char(Digit) when Digit >= $A, Digit =< $Z -> (Digit - $A) + 10. %% @spec from_datetime_rfc_1123() -> string() %% @equiv from_datetime_rfc_1123(calendar:universal_time()) from_datetime_rfc_1123() -> from_datetime_rfc_1123(calendar:universal_time()). %% @spec from_datetime_rfc_1123({date(), time()}) -> string() %% @doc Returns a date/time string formatted in accordance to RFC 1123. %% This sort of date/time looks like "Sun, 06 Nov 1994 08:23:19 GMT". from_datetime_rfc_1123({{Y, M, D}, {H, I, S}}) -> Dow = case calendar:day_of_the_week(Y, M, D) of 1 -> "Mon"; 2 -> "Tue"; 3 -> "Wed"; 4 -> "Thu"; 5 -> "Fri"; 6 -> "Sat"; 7 -> "Sun" end, Month = case M of 1 -> "Jan"; 2 -> "Feb"; 3 -> "Mar"; 4 -> "Apr"; 5 -> "May"; 6 -> "Jun"; 7 -> "Jul"; 8 -> "Aug"; 9 -> "Sep"; 10 -> "Oct"; 11 -> "Nov"; 12 -> "Dec" end, lists:flatten(io_lib:format( "~s, ~2.2.0w ~s ~w ~2.2.0w:~2.2.0w:~2.2.0w GMT", [Dow, D, Month, Y, H, I, S])). %%% END of openflax/string.erl %%%