Permalink
Browse files

Added iconv, needed for receiving e-mail.

  • Loading branch information...
1 parent ffbef8d commit 7baa61b2b47152306ce4e6b399555fe2bc39c201 @mworrell mworrell committed May 31, 2011
View
8 Makefile
@@ -4,18 +4,21 @@ EBIN_DIRS := $(wildcard deps/*/ebin)
APP := zotonic
PARSER =src/erlydtl/erlydtl_parser
-all: gen_smtp z_logger mochiweb webmachine module-deps $(PARSER).erl erl ebin/$(APP).app
+all: gen_smtp iconv z_logger mochiweb webmachine module-deps $(PARSER).erl erl ebin/$(APP).app
erl:
@$(ERL) -pa $(EBIN_DIRS) -pa ebin -noinput +B \
-eval 'case make:all() of up_to_date -> halt(0); error -> halt(1) end.'
$(PARSER).erl: $(PARSER).yrl
- $(ERLC) -o src/erlydtl src/erlydtl/erlydtl_parser.yrl
+ $(ERLC) -o src/erlydtl $(PARSER).yrl
gen_smtp:
cd deps/gen_smtp && $(MAKE)
+iconv:
+ cd deps/iconv && rake
+
z_logger:
cd deps/z_logger && $(MAKE)
@@ -39,6 +42,7 @@ clean:
(cd deps/z_logger; $(MAKE) clean)
(cd deps/mochiweb; $(MAKE) clean)
(cd deps/webmachine; $(MAKE) clean)
+ (cd deps/iconv; rake clean)
@if [ "`find modules/ -name Makefile`" != "" ]; then for f in "`ls modules/*/Makefile`"; do echo $$f; $(MAKE) -C `dirname $$f` clean; done; fi
@if [ "`find priv/modules/ -name Makefile`" != "" ]; then for f in "`ls priv/modules/*/Makefile`"; do echo $$f; $(MAKE) -C `dirname $$f` clean; done; fi
@if [ "`find priv/sites/*/modules/ -name Makefile`" != "" ]; then for f in "`ls priv/sites/*/modules/*/Makefile`"; do echo $$f; $(MAKE) -C `dirname $$f` clean; done; fi
View
22 deps/iconv/LICENSE
@@ -0,0 +1,22 @@
+
+Copyright (c) 2004, Torbjorn Tornkvist
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
View
76 deps/iconv/README.markdown
@@ -0,0 +1,76 @@
+About
+=====
+
+Erlang-iconv is a fork of the iconv in Jungerl. I pulled it out of jungerl
+because I only wanted iconv, not all the other stuff in jungerl and because the
+jungerl build system wasn't very helpful on anything but linux.
+
+erlang-iconv has been built and tested on the following platforms:
+
+* Linux
+* FreeBSD
+* OpenBSD
+* OSX
+
+It should also build on NetBSD and most other UNIX-like systems. I haven't
+bothered to try on windows yet.
+
+Usage
+=====
+
+Here's some sample usage converting some shift-jis text to utf-8:
+
+<pre>
+1&gt; iconv:start().
+{ok,&lt;0.53.0&gt;}
+2&gt; X = &lt;&lt;83,97,109,112,108,101,58,32,142,132,32,130,205,32,131,67,32,131,147,32,131,79,32,131,71,32,130,197,32,130,183,13,10&gt;&gt;.
+&lt;&lt;83,97,109,112,108,101,58,32,142,132,32,130,205,32,131,
+ 67,32,131,147,32,131,79,32,131,71,32,130,197,32,...&gt;&gt;
+3&gt; io:format("~s~n", [X]).
+Sample:
+ Í C O G Å ·
+
+ok
+4&gt; io:format("~ts~n", [X]).
+** exception exit: {badarg,[{io,format,
+ [&lt;0.25.0&gt;,"~ts~n",
+ [&lt;&lt;83,97,109,112,108,101,58,32,142,132,32,130,205,32,
+ 131,67,32,131,147,...&gt;&gt;]]},
+ {erl_eval,do_apply,5},
+ {shell,exprs,6},
+ {shell,eval_exprs,6},
+ {shell,eval_loop,3}]}
+ in function io:o_request/3
+5&gt; {ok, CD} = iconv:open("utf-8", "shift-jis").
+{ok,&lt;&lt;176,86,91,1,0,0,0,0&gt;&gt;}
+6&gt; {ok, Output} = iconv:conv(CD, X).
+{ok,&lt;&lt;83,97,109,112,108,101,58,32,231,167,129,32,227,129,
+ 175,32,227,130,164,32,227,131,179,32,227,130,176,
+ ...&gt;&gt;}
+7&gt; io:format("~ts~n", [Output]).
+Sample: 私 は イ ン グ エ で す
+8&gt; iconv:close(CD).
+ok
+</pre>
+
+As you can see, before we passed it through iconv it was an unprintable mess.
+
+Installation
+============
+
+To install, use rake:
+
+<pre>
+rake
+sudo rake install
+</pre>
+
+If the compilation of the C part fails with errors about iconv, you have to
+specify the prefix where iconv is located, for example on FreeBSD:
+
+<pre>
+rake iconv=/usr/local
+</pre>
+
+And if you don't have iconv or it's development header installed (and iconv
+isn't part of your C libary) install it.
View
317 deps/iconv/Rakefile
@@ -0,0 +1,317 @@
+require 'rake/clean'
+
+Dir['tasks/**/*.rake'].each { |rake| load rake }
+
+def percent_to_color(per)
+ if ENV['COLORTERM'].to_s.downcase == 'yes' or ENV['TERM'] =~ /-color$/
+ if per >= 90.0
+ colorstart = "\e[1;32m"
+ elsif per >= 75.0
+ colorstart = "\e[0;32m"
+ elsif per >= 50.0
+ colorstart = "\e[0;33m"
+ elsif per >= 25.0
+ colorstart = "\e[0;31m"
+ else
+ colorstart = "\e[1;31m"
+ end
+ return [colorstart, "\e[0m"]
+ else
+ return ["", ""]
+ end
+end
+
+
+ROOTDIR = `erl -noshell -eval 'io:format("~n~s~n", [code:root_dir()]).' -s erlang halt | tail -n 1`.chomp
+
+if RUBY_PLATFORM =~ /darwin/i
+ $C_FLAGS= "-fno-common -liconv -Wall -Wl,-bundle,-undefined,dynamic_lookup -arch x86_64 -arch i386 -fPIC -I#{ROOTDIR}/usr/include"
+elsif RUBY_PLATFORM =~ /linux/i or RUBY_PLATFORM =~ /netbsd/i
+ $C_FLAGS = "-shared -Wall -I#{ROOTDIR}/usr/include -fPIC"
+else
+ $C_FLAGS = "-shared -Wall -I#{ROOTDIR}/usr/include -fPIC -liconv"
+end
+
+if ENV['iconv']
+ $C_FLAGS += " -I#{ENV['iconv']}/include -L#{ENV['iconv']}/lib"
+end
+
+INCLUDE = "include"
+
+vertest = `erl -noshell -eval 'io:format("~n~s~n", [erlang:system_info(otp_release)]).' -s erlang halt | tail -n 1`.chomp
+if vertest =~ /(R\d\d[AB])/
+ OTPVERSION = $1
+else
+ STDERR.puts "unable to determine OTP version! (I got #{vertest})"
+ exit -1
+end
+ERLC_FLAGS = "-I#{INCLUDE} -D #{OTPVERSION} +warn_unused_vars +warn_unused_import +warn_exported_vars +warn_untyped_record"
+
+C_SRC = FileList['c_src/*.c']
+SRC = FileList['src/*.erl']
+HEADERS = FileList['include/*.hrl']
+C_HEADERS = FileList['c_src/*.h']
+OBJ = SRC.pathmap("%{src,ebin}X.beam")
+#C_OBJ = C_SRC.pathmap("%{c_src,priv}X.o")
+CONTRIB = FileList['contrib/*']
+DEBUGOBJ = SRC.pathmap("%{src,debug_ebin}X.beam")
+COVERAGE = SRC.pathmap("%{src,coverage}X.txt")
+RELEASE = FileList['src/*.rel.src'].pathmap("%{src,ebin}X")
+
+# check to see if gmake is available, if not fall back on the system make
+if res = `which gmake` and $?.exitstatus.zero? and not res =~ /no gmake in/
+ MAKE = File.basename(res.chomp)
+else
+ MAKE = 'make'
+end
+
+@maxwidth = SRC.map{|x| File.basename(x, 'erl').length}.max
+
+CLEAN.include("ebin/*.beam")
+CLEAN.include("ebin/*.app")
+CLEAN.include("ebin/*.script")
+CLEAN.include("ebin/*.boot")
+CLEAN.include("ebin/*.rel")
+CLEAN.include("debug_ebin/*.beam")
+CLEAN.include("debug_ebin/*.app")
+CLEAN.include("debug_ebin/*.script")
+CLEAN.include("debug_ebin/*.boot")
+CLEAN.include("coverage/*.txt")
+CLEAN.include("coverage/*.txt.failed")
+CLEAN.include("coverage/*.html")
+CLEAN.include("doc/*.html")
+CLEAN.include("c_src/*.o")
+CLEAN.include("priv/*")
+
+verbose(true) unless ENV['quiet']
+
+directory 'ebin'
+directory 'priv'
+directory 'debug_ebin'
+directory 'coverage'
+#directory 'doc'
+
+rule ".beam" => ["%{ebin,src}X.erl"] + HEADERS do |t|
+ sh "erlc -pa ebin -W #{ERLC_FLAGS} +warn_missing_spec -o ebin #{t.source} "
+end
+
+rule ".beam" => ["%{debug_ebin,src}X.erl"] + HEADERS do |t|
+ sh "erlc +debug_info -D TEST -pa debug_ebin -W #{ERLC_FLAGS} -o debug_ebin #{t.source} "
+end
+
+rule ".rel" => ["%{ebin,src}X.rel.src"] do |t|
+ contents = File.read(t.source)
+ #p contents
+ while contents =~ /^[\s\t]*([-a-zA-Z0-9_]+),[\s\t]*$/
+ app = $1
+ if app == "erts"
+ version = `erl -noshell -eval 'io:format("~n~s~n", [erlang:system_info(version)]).' -s erlang halt | tail -n 1`.chomp
+ else
+ version = `erl -noshell -eval 'application:load(#{app}), io:format("~n~s~n", [proplists:get_value(#{app}, lists:map(fun({Name, Desc, Vsn}) -> {Name, Vsn} end, application:loaded_applications()))]).' -s erlang halt | tail -n 1`.chomp
+ end
+ if md = /(\d+\.\d+(\.\d+(\.\d+|)|))/.match(version)
+ contents.sub!(app, "{#{app}, \"#{md[1]}\"}")
+ else
+ STDERR.puts "Cannot find application #{app} mentioned in release file!"
+ exit 1
+ end
+ end
+ File.open(t.name, 'w') do |f|
+ f.puts contents
+ end
+end
+
+rule ".so" => ["%{priv,c_src}X.c"] + C_HEADERS do |t|
+ sh "gcc #{$C_FLAGS} #{t.source} -o #{t.to_s}"
+end
+
+rule ".txt" => ["%{coverage,debug_ebin}X.beam"] do |t|
+ mod = File.basename(t.source, '.beam')
+ if ENV['modules'] and not ENV['modules'].split(',').include? mod
+ puts "skipping tests for #{mod}"
+ next
+ end
+
+ print " #{mod.ljust(@maxwidth - 1)} : "
+ STDOUT.flush
+ test_output = `erl -noshell -pa debug_ebin -pa contrib/mochiweb/ebin -sname testpx -eval ' cover:start(), cover:compile_beam("#{t.source}"), try eunit:test(#{mod}, [verbose]) of _Any -> cover:analyse_to_file(#{mod}, "coverage/#{mod}.txt"), cover:analyse_to_file(#{mod}, "coverage/#{mod}.html", [html]) catch _:_ -> io:format("This module does not provide a test() function~n"), ok end.' -s erlang halt`
+ if /(All \d+ tests (successful|passed)|There were no tests to run|This module does not provide a test\(\) function|Test (successful|passed))/ =~ test_output
+ File.delete(t.to_s+'.failed') if File.exists?(t.to_s+'.failed')
+ if ENV['verbose']
+ puts test_output.split("\n")[1..-1].map{|x| x.include?('1>') ? x.gsub(/\([a-zA-Z0-9\-@]+\)1>/, '') : x}.join("\n")
+ else
+ out = $1
+ if /(All \d+ tests (successful|passed)|Test (successful|passed))/ =~ test_output
+ colorstart, colorend = percent_to_color(80)
+ #elsif /This module does not provide a test\(\) function/ =~ test_output
+ #colorstart, colorend = percent_to_color(50)
+ else
+ colorstart, colorend = percent_to_color(50)
+ #colorstart, colorend = ["", ""]
+ end
+ puts "#{colorstart}#{out}#{colorend}"
+ #puts " #{mod.ljust(@maxwidth - 1)} : #{out}"
+ end
+ else
+ puts "\e[1;35mFAILED\e[0m"
+ puts test_output.split("\n")[1..-1].map{|x| x.include?('1>') ? x.gsub(/\([a-zA-Z0-9\-@]+\)1>/, '') : x}.join("\n")
+ puts " #{mod.ljust(@maxwidth - 1)} : \e[1;35mFAILED\e[0m"
+ File.delete(t.to_s) if File.exists?(t.to_s)
+ File.new(t.to_s+'.failed', 'w').close
+ end
+end
+
+task :compile => [:contrib, 'ebin', 'priv'] + HEADERS + OBJ + ['priv/iconv_drv.so'] + RELEASE do
+ Dir["ebin/*.rel"].each do |rel|
+ rel = File.basename(rel, '.rel')
+ sh "erl -noshell -eval 'systools:make_script(\"ebin/#{rel}\", [{outdir, \"ebin\"}]).' -s erlang halt -pa ebin"
+ end
+end
+
+task :install => [:compile] do
+ sh "mkdir #{ROOTDIR}/lib/iconv-1.0.1" unless File.directory? "#{ROOTDIR}/lib/iconv-1.0.1"
+ sh "cp -r src ebin c_src priv #{ROOTDIR}/lib/iconv-1.0.1"
+end
+
+task :contrib do
+ CONTRIB.each do |cont|
+ if File.exists? File.join(cont, 'Makefile')
+ sh "#{MAKE} -C #{cont}"
+ elsif File.exists? File.join(cont, 'Rakefile')
+ pwd = Dir.pwd
+ Dir.chdir(cont)
+ sh "#{$0}"
+ Dir.chdir(pwd)
+ end
+ end
+ unless Dir["src/*.app"].length.zero?
+ sh "cp src/*.app ebin/"
+ end
+end
+
+task :default => :compile
+
+task :release => :compile
+
+desc "Alias for test:all"
+task :test => "test:all"
+
+desc "Generate Documentation"
+task :doc do
+ sh('mkdir doc') unless File.directory? 'doc'
+ sh("rm -rf doc/*.html && cd doc && erl -noshell -run edoc files ../#{SRC.join(" ../")} -run init stop")
+end
+
+namespace :test do
+ desc "Compile .beam files with -DTEST and +debug_info => debug_ebin"
+ task :compile => [:contrib, 'debug_ebin'] + HEADERS + DEBUGOBJ + ['priv/iconv_drv.so']
+
+ task :contrib do
+ CONTRIB.each do |cont|
+ if File.exists? File.join(cont, 'Makefile')
+ sh "#{MAKE} -C #{cont}"
+ elsif File.exists? File.join(cont, 'Rakefile')
+ pwd = Dir.pwd
+ Dir.chdir(cont)
+ sh "#{$0} debug=yes"
+ Dir.chdir(pwd)
+ end
+ end
+ unless Dir["src/*.app"].length.zero?
+ sh "cp src/*.app debug_ebin/"
+ end
+ end
+
+ desc "run eunit tests and output coverage reports"
+ task :all => [:compile, :eunit, :report_coverage]
+
+ desc "run only the eunit tests"
+ task :eunit => [:compile, 'coverage'] + COVERAGE
+
+ desc "rerun any outstanding tests and report the coverage"
+ task :report_coverage => [:eunit, :report_current_coverage]
+
+ desc "report the percentage code coverage of the last test run"
+ task :report_current_coverage do
+ global_total = 0
+ files = (Dir['coverage/*.txt'] + Dir['coverage/*.txt.failed']).sort
+ maxwidth = files.map{|x| x = File.basename(x, '.failed'); File.basename(x, ".txt").length}.max
+ puts "Code coverage:"
+ files.each do |file|
+ if file =~ /\.txt\.failed$/
+ if ENV['COLORTERM'].to_s.downcase == 'yes' or ENV['TERM'] =~ /-color$/
+ puts " #{File.basename(file, ".txt.failed").ljust(maxwidth)} : \e[1;35mFAILED\e[0m"
+ else
+ puts " #{File.basename(file, ".txt.failed").ljust(maxwidth)} : FAILED"
+ end
+ else
+ total = 0
+ tally = 0
+ File.read(file).each do |line|
+ if line =~ /^\s+[1-9][0-9]*\.\./
+ total += 1
+ tally += 1
+ elsif line =~ /^\s+0\.\./ and not line =~ /^-module/
+ total += 1
+ end
+ end
+ per = tally/total.to_f * 100
+ colorstart, colorend = percent_to_color(per)
+ puts " #{File.basename(file, ".txt").ljust(maxwidth)} : #{colorstart}#{sprintf("%.2f%%", (tally/(total.to_f)) * 100)}#{colorend}"
+ global_total += (tally/(total.to_f)) * 100
+ end
+ end
+ colorstart, colorend = percent_to_color(global_total/files.length)
+ puts "Overall coverage: #{colorstart}#{sprintf("%.2f%%", global_total/files.length)}#{colorend}"
+ end
+
+ task :report_missing_specs do
+ unspecced = []
+ ignored = %w{handle_info handle_cast handle_call code_change terminate init}
+ puts "Functions missing specs:"
+ SRC.each do |src|
+ contents = File.read(src)
+ contents.each do |line|
+ if md = /^([a-z_]+)\(.*?\) ->/.match(line) and not ignored.include?(md[1]) and not md[1][-5..-1] == '_test' and not md[1][-6..-1] == '_test_'
+ unless /^-spec\(#{md[1]}\//.match(contents)
+ unspecced << File.basename(src, '.erl') + ':'+ md[1]
+ end
+ end
+ end
+ end
+ puts " "+unspecced.uniq.join("\n ")
+ end
+
+ desc "run the dialyzer"
+ task :dialyzer do
+ print "running dialyzer..."
+ `dialyzer --check_plt`
+ if $?.exitstatus != 0
+ puts 'no PLT'
+ puts "The dialyzer can't find the initial PLT, you can try building one using `rake test:build_plt`. This can take quite some time."
+ exit(1)
+ end
+ STDOUT.flush
+ # Add -DEUNIT=1 here to make dialyzer evaluate the code in the test cases. This generates some spurious warnings so
+ # it's not set normally but it can be very helpful occasionally.
+ dialyzer_flags = ""
+ dialyzer_flags += " -DTEST=1" if ENV['dialyzer_debug']
+ dialyzer_flags += " -Wunderspecs" if ENV['dialyzer_underspecced']
+ contribfiles = Dir['contrib**/*.erl'].join(' ')
+ dialyzer_output = `dialyzer -D#{OTPVERSION}=1 #{dialyzer_flags} --src -I include -c #{SRC.join(' ')} #{contribfiles}`
+ #puts dialyzer_output
+ if $?.exitstatus.zero?
+ puts 'ok'
+ else
+ puts 'not ok'
+ puts dialyzer_output
+ end
+ end
+
+ desc "try to create the dialyzer's initial PLT"
+ task :build_plt do
+ out = `which erlc`
+ foo = out.split('/')[0..-3].join('/')+'/lib/erlang/lib'
+ sh "dialyzer --build_plt -r #{foo}/kernel*/ebin #{foo}/stdlib*/ebin #{foo}/mnesia*/ebin #{foo}/crypto*/ebin #{foo}/eunit*/ebin"
+ end
+end
View
371 deps/iconv/c_src/iconv_drv.c
@@ -0,0 +1,371 @@
+/* Created : 23 Mar 2004 by Tobbe <tobbe@bluetail.com>
+ * Description : iconv driver - conversion between character sets
+ *
+ * $Id$
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iconv.h>
+#include <errno.h>
+
+#include "erl_driver.h"
+#ifndef ERL_DRV_NIL
+#include "erl_driver_compat.h"
+#endif
+
+/* op codes */
+#define IV_OPEN 'o'
+#define IV_CONV 'v'
+#define IV_CLOSE 'c'
+
+/* convert buffers */
+#define INBUF_SZ 512
+#define OUTBUF_SZ INBUF_SZ*4
+/*static char inbuf[INBUF_SZ];*/
+//static char outbuf[OUTBUF_SZ];
+
+
+/* these should really be defined in driver.h */
+#define LOAD_ATOM(vec, i, atom) \
+ (((vec)[(i)] = ERL_DRV_ATOM), \
+ ((vec)[(i)+1] = (atom)), \
+ (i+2))
+
+#define LOAD_INT(vec, i, val) \
+ (((vec)[(i)] = ERL_DRV_INT), \
+ ((vec)[(i)+1] = (ErlDrvTermData)(val)), \
+ (i+2))
+
+#define LOAD_PORT(vec, i, port) \
+ (((vec)[(i)] = ERL_DRV_PORT), \
+ ((vec)[(i)+1] = (port)), \
+ (i+2))
+
+#define LOAD_PID(vec, i, pid) \
+ (((vec)[(i)] = ERL_DRV_PID), \
+ ((vec)[(i)+1] = (pid)), \
+ (i+2))
+
+#define LOAD_BINARY(vec, i, bin, offs, len) \
+ (((vec)[(i)] = ERL_DRV_BINARY), \
+ ((vec)[(i)+1] = (ErlDrvTermData)(bin)), \
+ ((vec)[(i)+2] = (len)), \
+ ((vec)[(i)+3] = (offs)), \
+ (i+4))
+
+#define LOAD_STRING(vec, i, str, len) \
+ (((vec)[(i)] = ERL_DRV_STRING), \
+ ((vec)[(i)+1] = (ErlDrvTermData)(str)), \
+ ((vec)[(i)+2] = (len)), \
+ (i+3))
+
+#define LOAD_STRING_CONS(vec, i, str, len) \
+ (((vec)[(i)] = ERL_DRV_STRING_CONS), \
+ ((vec)[(i)+1] = (ErlDrvTermData)(str)), \
+ ((vec)[(i)+2] = (len)), \
+ (i+3))
+
+#define LOAD_TUPLE(vec, i, size) \
+ (((vec)[(i)] = ERL_DRV_TUPLE), \
+ ((vec)[(i)+1] = (size)), \
+ (i+2))
+
+#define LOAD_LIST(vec, i, size) \
+ (((vec)[(i)] = ERL_DRV_LIST), \
+ ((vec)[(i)+1] = (size)), \
+ (i+2))
+
+static int driver_send_bin();
+
+/* atoms which are sent to erlang */
+static ErlDrvTermData am_ok;
+static ErlDrvTermData am_value;
+static ErlDrvTermData am_error;
+static ErlDrvTermData am_enomem;
+static ErlDrvTermData am_einval;
+static ErlDrvTermData am_eilseq;
+static ErlDrvTermData am_e2big;
+static ErlDrvTermData am_unknown;
+
+static ErlDrvEntry iconvdrv_driver_entry;
+
+typedef struct t_iconvdrv {
+ ErlDrvPort port;
+ ErlDrvTermData dport; /* the port identifier as ErlDrvTermData */
+ unsigned char digest[16];
+} t_iconvdrv;
+
+
+static ErlDrvData iconvdrv_start(ErlDrvPort port, char *buf)
+{
+ t_iconvdrv *iconv = (t_iconvdrv*) driver_alloc(sizeof(t_iconvdrv));
+
+ if (iconv == NULL) return (ErlDrvData) -1;
+ iconv->port = port;
+ iconv->dport = driver_mk_port(port);
+ return (ErlDrvData) iconv;
+}
+
+static void iconvdrv_stop(ErlDrvData drv_data)
+{
+ t_iconvdrv *iv = (t_iconvdrv*) drv_data;
+ driver_free(iv);
+}
+
+
+/* send {P, value, Bin} to caller */
+static int driver_send_bin(t_iconvdrv *iv, ErlDrvBinary *bin, int len)
+{
+ int i = 0;
+ ErlDrvTermData to, spec[10];
+
+ to = driver_caller(iv->port);
+
+ i = LOAD_PORT(spec, i, iv->dport);
+ i = LOAD_ATOM(spec, i, am_value);
+ i = LOAD_BINARY(spec, i, bin, 0, len);
+ i = LOAD_TUPLE(spec, i, 3);
+
+ return driver_send_term(iv->port, to, spec, i);
+}
+
+/* send {P, ok} to caller */
+static int driver_send_ok(t_iconvdrv *iv)
+{
+ int i = 0;
+ ErlDrvTermData to, spec[10];
+
+ to = driver_caller(iv->port);
+
+ i = LOAD_PORT(spec, i, iv->dport);
+ i = LOAD_ATOM(spec, i, am_ok);
+ i = LOAD_TUPLE(spec, i, 2);
+
+ return driver_send_term(iv->port, to, spec, i);
+}
+
+/* send {P, error, Error} to caller */
+static int driver_send_error(t_iconvdrv *iv, ErlDrvTermData *am)
+{
+ int i = 0;
+ ErlDrvTermData to, spec[8];
+
+ to = driver_caller(iv->port);
+
+ i = LOAD_PORT(spec, i, iv->dport);
+ i = LOAD_ATOM(spec, i, am_error);
+ i = LOAD_ATOM(spec, i, *am);
+ i = LOAD_TUPLE(spec, i, 3);
+
+ return driver_send_term(iv->port, to, spec, i);
+}
+
+#define CODE_STR_SZ 64
+
+#define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \
+ (((unsigned char*) (s))[1]))
+
+
+#define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
+ ((unsigned char*)(s))[1] = (i) & 0xff;}
+
+static void iv_open(t_iconvdrv *iv, char *tocode, char *fromcode)
+{
+ int len;
+ iconv_t cd;
+ ErlDrvBinary *bin;
+
+ if ((cd = iconv_open(tocode, fromcode)) == (iconv_t) -1) {
+ driver_send_error(iv, &am_einval);
+ }
+ else {
+ len = sizeof(iconv_t);
+ if (!(bin = driver_alloc_binary(len+1))) {
+ iconv_close(cd);
+ driver_send_error(iv, &am_enomem);
+ }
+ else {
+ memcpy(bin->orig_bytes, &cd, len);
+ if (!strcasecmp(tocode + strlen(tocode) -6, "IGNORE")) {
+ /* GLIBC's iconv is annoying and will throw the failure code for
+ * invalid sequences even though we specify //IGNORE so we have to
+ * keep track if we initalized this conversion handle with //IGNORE
+ * or not so we can disregard the error. */
+ bin->orig_bytes[len] = 1;
+ } else {
+ bin->orig_bytes[len] = 0;
+ }
+ driver_send_bin(iv, bin, len+1);
+ driver_free_binary(bin);
+ }
+ }
+
+ return;
+}
+
+static void iv_conv(t_iconvdrv *iv, iconv_t cd, char *ip, size_t ileft, char ignore)
+{
+ size_t oleft=ileft;
+ char *op, *buf;
+ int olen = ileft + 1;
+ ErlDrvBinary *bin;
+
+ /* malloc enough for the input size +1 (null terminated),
+ * with the assumption that the output length will be close to the input
+ * length. This isn't always the case, but we realloc on E2BIG below. */
+ buf = malloc(olen);
+
+ if (!buf) {
+ driver_send_error(iv, &am_enomem);
+ return;
+ }
+
+ op = buf;
+
+ /* Reset cd to initial state */
+ iconv(cd, NULL, NULL, NULL, NULL);
+
+ while (iconv(cd, &ip, &ileft, &op, &oleft) == (size_t) -1 &&
+ !(ignore && errno == EILSEQ)) {
+ if (errno == EILSEQ) {
+ driver_send_error(iv, &am_eilseq);
+ } else if (errno == EINVAL) {
+ driver_send_error(iv, &am_einval);
+ } else if (errno == E2BIG) {
+ char *newbuf;
+ /* allocate as much additional space as iconv says we need */
+ newbuf = realloc(buf, olen + ileft + oleft);
+ if (!newbuf) {
+ free(buf); /* realloc failed, make sure we free the old buffer*/
+ driver_send_error(iv, &am_enomem);
+ return;
+ }
+ buf = newbuf;
+ op = buf + (olen - oleft - 1);
+ olen += ileft + oleft;
+ oleft += ileft;
+ /* keep going */
+ continue;
+ } else {
+ driver_send_error(iv, &am_unknown);
+ }
+ return;
+ }
+ *(op++) = 0; /* ensure we null terminate */
+
+ if (ileft == 0) {
+ /* find the length of the result, minus the terminating NULL */
+ olen = strlen(buf);
+ if (!(bin = driver_alloc_binary(olen))) {
+ driver_send_error(iv, &am_enomem);
+ } else {
+ memcpy(bin->orig_bytes, buf, olen);
+ driver_send_bin(iv, bin, olen);
+ driver_free_binary(bin);
+ }
+ }
+
+ free(buf);
+
+ return;
+}
+
+static void iv_close(t_iconvdrv *iv, iconv_t cd)
+{
+ iconv_close(cd);
+ driver_send_ok(iv);
+ return;
+}
+
+static void iconvdrv_from_erlang(ErlDrvData drv_data, char *buf, int len)
+{
+ t_iconvdrv *iv = (t_iconvdrv *) drv_data;
+ char ignore = 0;
+ char tocode[CODE_STR_SZ], fromcode[CODE_STR_SZ];
+ char *bp=buf;
+ unsigned int i=0;
+ iconv_t cd;
+
+ i = bp[0];
+ bp++;
+ switch (i) {
+
+ case IV_OPEN: {
+ /*
+ * Format: <to-len:16><tocode><from-len:16><from-buf>
+ */
+ i = get_int16(bp);
+ bp += 2;
+ memcpy(tocode, bp, i);
+ tocode[i] = '\0';
+ bp += i;
+ i = get_int16(bp);
+ bp += 2;
+ memcpy(fromcode, bp, i);
+ fromcode[i] = '\0';
+
+ iv_open(iv, tocode, fromcode);
+ break;
+ }
+
+ case IV_CONV: {
+ /*
+ * Format: <cd-len:16><cd><ignore><buf-len:16><buf>
+ */
+ i = get_int16(bp);
+ bp += 2;
+ memcpy(&cd, bp, i-1);
+ memcpy(&ignore, bp + i -1, 1);
+ bp += i;
+ i = get_int16(bp);
+ bp += 2;
+
+ iv_conv(iv, cd, bp, i, ignore);
+ break;
+ }
+
+ case IV_CLOSE: {
+ /*
+ * Format: <cd-len:16><cd><ignore>
+ */
+ i = get_int16(bp);
+ bp += 2;
+ memcpy(&cd, bp, i - 1);
+
+ iv_close(iv, cd);
+ break;
+ }
+
+ } /* switch */
+
+ return;
+}
+
+
+/*
+ * Initialize and return a driver entry struct
+ */
+
+DRIVER_INIT(iconvdrv)
+{
+ am_ok = driver_mk_atom("ok");
+ am_value = driver_mk_atom("value");
+ am_error = driver_mk_atom("error");
+ am_enomem = driver_mk_atom("enomem");
+ am_einval = driver_mk_atom("einval");
+ am_eilseq = driver_mk_atom("eilseq");
+ am_e2big = driver_mk_atom("e2big");
+ am_unknown = driver_mk_atom("unknown");
+
+ iconvdrv_driver_entry.init = NULL; /* Not used */
+ iconvdrv_driver_entry.start = iconvdrv_start;
+ iconvdrv_driver_entry.stop = iconvdrv_stop;
+ iconvdrv_driver_entry.output = iconvdrv_from_erlang;
+ iconvdrv_driver_entry.ready_input = NULL;
+ iconvdrv_driver_entry.ready_output = NULL;
+ iconvdrv_driver_entry.driver_name = "iconv_drv";
+ iconvdrv_driver_entry.finish = NULL;
+ iconvdrv_driver_entry.outputv = NULL;
+ return &iconvdrv_driver_entry;
+}
View
BIN deps/iconv/rebar
Binary file not shown.
View
3 deps/iconv/rebar.config
@@ -0,0 +1,3 @@
+{port_envs, [{"darwin|openbsd", "LDFLAGS", "$LDFLAGS -liconv"},
+ {"openbsd", "CFLAGS", "$CFLAGS -I/usr/local/include"},
+ {"openbsd", "LDFLAGS", "$LDFLAGS -L/usr/local/lib"}]}.
View
10 deps/iconv/src/iconv.app.src
@@ -0,0 +1,10 @@
+{application,iconv,
+ [{description,"Interface to the iconv character set convertion library"},
+ {vsn,"1.0.1"},
+ {modules,[]},
+ {registered,[iconv]},
+ {env, []},
+ {mod, {iconv_app, []}},
+ {applications, []},
+ {dependencies, []}]}.
+
View
218 deps/iconv/src/iconv.erl
@@ -0,0 +1,218 @@
+-module(iconv).
+%%%----------------------------------------------------------------------
+%%% File : iconv.erl
+%%% Author : Torbjorn Tornkvist <tobbe@bluetail.com>
+%%% Purpose : iconv support
+%%% Created : 23 Mar 2004 by <tobbe@bluetail.com>
+%%%
+%%% $Id$
+%%%----------------------------------------------------------------------
+-behaviour(gen_server).
+-export([start/0, start_link/0, stop/0, open/2, conv/2, close/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(state, {port}).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+
+%%% op codes
+-define(IV_OPEN, $o).
+-define(IV_CONV, $v).
+-define(IV_CLOSE, $c).
+
+-define(INBUF_SZ, 512).
+
+-define(DRV_NAME, "iconv_drv").
+-define(SERVER, ?MODULE).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start() ->
+ gen_server:start({local, ?SERVER}, ?MODULE, [], []).
+
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+stop() ->
+ gen_server:call(?SERVER, stop).
+
+%%open(To, From) -> {ok, ballen};
+open(To, From) ->
+ gen_server:call(?SERVER, {open, l2b(To), l2b(From)}, infinity).
+
+%%conv(Cd, String) -> {ok, l2b(String)};
+conv(Cd, String) when is_binary(Cd) ->
+ gen_server:call(?SERVER, {conv, Cd, l2b(String)}, infinity).
+
+%%close(Cd) -> ok;
+close(Cd) when is_binary(Cd) ->
+ gen_server:call(?SERVER, {close, Cd}, infinity).
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+init([]) ->
+ erl_ddll:start(),
+ Path = case code:priv_dir(iconv) of
+ {error, _} ->
+ case load_path(?DRV_NAME++".so") of
+ {error, _} ->
+ error;
+ {ok, P} ->
+ P
+ end;
+ P ->
+ P
+ end,
+
+ case Path of
+ error ->
+ {stop, no_driver};
+ Path ->
+ case erl_ddll:load_driver(Path, ?DRV_NAME) of
+ ok ->
+ Port = open_port({spawn, ?DRV_NAME}, [binary]),
+ {ok, #state{port = Port}};
+ {error, Error} ->
+ error_logger:format("Error loading driver: " ++ erl_ddll:format_error(Error), []),
+ {stop, bad_driver}
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_call({open, To, From}, _, S) ->
+ ToLen = byte_size(To),
+ FromLen = byte_size(From),
+ Msg = <<?IV_OPEN,ToLen:16,To/binary,FromLen:16,From/binary>>,
+ Reply = call_drv(S#state.port, Msg),
+ {reply, Reply, S};
+%%
+handle_call({conv, Cd, Buf}, _, S) ->
+ CdLen = byte_size(Cd),
+ BufLen = byte_size(Buf),
+ Msg = <<?IV_CONV,CdLen:16,Cd/binary,BufLen:16,Buf/binary>>,
+ Reply = call_drv(S#state.port, Msg),
+ {reply, Reply, S};
+
+%%
+handle_call({close, Cd}, _, S) ->
+ CdLen = byte_size(Cd),
+ Msg = <<?IV_CLOSE,CdLen:16,Cd/binary>>,
+ Reply = call_drv(S#state.port, Msg),
+ {reply, Reply, S};
+
+handle_call(stop, _, S) ->
+ {stop, normal, ok, S}.
+
+call_drv(Port, Msg) ->
+ erlang:port_command(Port, [Msg]),
+ recv(Port).
+
+recv(Port) ->
+ receive
+ {Port, ok} ->
+ ok;
+ {Port, value, Bin} ->
+ {ok,Bin};
+ {Port, error, ErrAtom} ->
+ {error, ErrAtom}
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+code_change(_, _, _) ->
+ ok.
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+load_path(File) ->
+ case lists:zf(fun(Ebin) ->
+ Priv = Ebin ++ "/../priv/",
+ case file:read_file_info(Priv ++ File) of
+ {ok, _} -> {true, Priv};
+ _ -> false
+ end
+ end, code:get_path()) of
+ [Dir|_] ->
+ {ok, Dir};
+ [] ->
+ error_logger:format("Error: ~s not found in code path\n", [File]),
+ {error, enoent}
+ end.
+
+l2b(L) when is_list(L) -> list_to_binary(L);
+l2b(B) when is_binary(B) -> B.
+
+-ifdef(TEST).
+
+smtp_session_test_() ->
+ {setup,
+ fun() ->
+ iconv:start()
+ end,
+ fun(_) ->
+ iconv:stop()
+ end,
+ [
+ {"Convert from latin-1 to utf-8",
+ fun() ->
+ {ok, CD} = iconv:open("utf-8", "ISO-8859-1"),
+ ?assertEqual({ok, <<"hello world">>}, iconv:conv(CD, "hello world")),
+ iconv:close(CD)
+ end
+ }
+ ]
+ }.
+
+
+ -endif.
View
10 deps/iconv/src/iconv_app.erl
@@ -0,0 +1,10 @@
+-module(iconv_app).
+
+-export([start/2, stop/0]).
+
+
+start(normal, []) ->
+ iconv:start().
+
+stop() ->
+ iconv:stop().

0 comments on commit 7baa61b

Please sign in to comment.