Packages

Character Code Converter

Current section

Files

Jump to
ccc c_src iconv_nif.c
Raw

c_src/iconv_nif.c

#include <errno.h>
#include <string.h>
#include <erl_nif.h>
#include <iconv.h>
#include "utils.h"
static ERL_NIF_TERM ccc_iconv_convert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary input, from_code, to_code;
enif_inspect_binary(env, argv[1], &from_code);
enif_inspect_binary(env, argv[2], &to_code);
char* from = malloc(from_code.size * (sizeof(char)+1));
from = strcpy(from, (const char*)from_code.data);
from[from_code.size] = '\0';
char* to = malloc(to_code.size * (sizeof(char)+1));
to = strcpy(to, (const char*)to_code.data);
to[to_code.size] = '\0';
iconv_t cd = iconv_open((const char*)to, (const char*)from);
free(from);
free(to);
if ((int)cd == -1) {
if (errno == EINVAL) {
char* message = "invalid from_code and/or to_code";
return utils_error_message(env, message);
}
}
enif_inspect_binary(env, argv[0], &input);
size_t inbytes_left = input.size;
size_t outbytes_left = 4*inbytes_left;
char* out_buf = calloc(outbytes_left, 1);
char* output = out_buf;
int res = (int)iconv(cd, (char **)(&input.data), &inbytes_left, &out_buf, &outbytes_left);
if (res == -1) {
switch(errno) {
case EILSEQ:
return utils_error_message(env, "invalid multibyte sequence");
case EINVAL:
return utils_error_message(env, "incomplete multibyte sequence");
case E2BIG:
return utils_error_message(env, "no more room");
default:
return utils_error_message(env, strerror(errno));
}
}
res = (int)iconv_close(cd);
if (res == -1) {
return utils_error_message(env, strerror(errno));
}
return utils_chars_to_binary(env, (const unsigned char*)output, strlen(output));
}
static ErlNifFunc nif_functions[] = {
{"convert", 3, ccc_iconv_convert}
};
ERL_NIF_INIT(Elixir.CCC, nif_functions, 0, 0, 0, NULL);