%% @author Marc Worrell %% @copyright 2013 Marc Worrell %% @doc Encode a list of values using CSV %% @end %% Copyright 2013 Marc Worrell %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -module(export_encode_csv). -author("Marc Worrell "). -export([ encode/2, encode/3 ]). -include_lib("zotonic_core/include/zotonic.hrl"). encode(V, Context) -> encode(V, true, Context). encode([], _IsRaw, _Context) -> <<"\r\n">>; encode([V], IsRaw, Context) -> iolist_to_binary([ encode_value(V, IsRaw, Context), <<"\r\n">> ]); encode([V|Xs], IsRaw, Context) -> iolist_to_binary([ encode_value(V, IsRaw, Context), [ [$,, encode_value(X, IsRaw, Context)] || X <- Xs ], <<"\r\n">> ]). encode_value(undefined, _IsRaw, _Context) -> <<>>; encode_value(<<>>, _IsRaw, _Context) -> <<>>; encode_value(N, _IsRaw, _Context) when is_integer(N) -> z_convert:to_binary(N); encode_value(N, _IsRaw, _Context) when is_float(N) -> z_convert:to_binary(N); encode_value(B, true, _Context) when is_binary(B) -> quote(escape(B)); encode_value(B, false, _Context) when is_binary(B) -> B1 = z_html:unescape(z_html:strip(B)), quote(escape(B1)); encode_value({Y,M,D} = Date, _IsRaw, Context) when is_integer(Y), is_integer(M), is_integer(D) -> quote(z_datetime:format_utc({Date, {0,0,0}}, "Y-m-d", Context)); encode_value(?ST_JUTTEMIS, _IsRaw, _Context) -> <<>>; encode_value({{9999,M,D}, {H,I,S}}, _IsRaw, _Context) when is_integer(M), is_integer(D), is_integer(H), is_integer(I), is_integer(S) -> <<>>; encode_value({{Y,M,D}, {H,I,S}} = Date, _IsRaw, Context) when is_integer(Y), is_integer(M), is_integer(D), is_integer(H), is_integer(I), is_integer(S) -> try quote(z_datetime:format(Date, "Y-m-d H:i:s", Context)) catch _:_ -> quote(z_datetime:format_utc(Date, "Y-m-d H:i:s", Context)) end; encode_value({trans, _} = Trans, IsRaw, Context) -> encode_value(z_trans:lookup_fallback(Trans, Context), IsRaw, Context); encode_value(N, IsRaw, Context) -> encode_value(z_convert:to_binary(N), IsRaw, Context). quote(B) -> [$", B, $"]. % We need to recognize fields starting with a '=', as Excel thinks that is a formula. escape(<<$=, B/binary>>) -> escape(B, <<" =">>); escape(B) -> escape(B, <<>>). escape(<<>>, Acc) -> Acc; escape(<<$", B/binary>>, Acc) -> escape(B, <>); escape(<<10, B/binary>>, Acc) -> escape(B, <>); escape(<<13, 10, B/binary>>, Acc) -> escape(B, <>); escape(<<13, B/binary>>, Acc) -> escape(B, <>); escape(<>, Acc) when X < 32 -> escape(B, Acc); escape(<>, Acc) -> escape(B, <>).