ERL_NIF_TERM date_diff_field(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { UErrorCode status = U_ZERO_ERROR; UCalendar* cal; cloner* ptr; double startMs, targetMs; char value[ATOM_LEN]; int parsed_value, amount; UCalendarDateFields field; if(!((argc == 4) && enif_get_resource(env, argv[0], calendar_type, (void**) &ptr) && enif_get_double(env, argv[1], &startMs) && enif_get_double(env, argv[2], &targetMs) && enif_get_atom(env, argv[3], (char*) value, ATOM_LEN, ERL_NIF_LATIN1))) { return enif_make_badarg(env); } cal = (UCalendar*) cloner_get(ptr); CHECK_RES(env, cal); ucal_setMillis(cal, (UDate) startMs, &status); CHECK(env, status); parsed_value = parseCalendarDateField(value); if (parsed_value == -1) { status = U_ILLEGAL_ARGUMENT_ERROR; CHECK(env, status); } field = (UCalendarDateFields) parsed_value; amount = (int) dateFieldDifference(cal, targetMs, field, status); CHECK(env, status); return enif_make_int(env, amount); }
ERL_NIF_TERM date_diff_fields(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { UErrorCode status = U_ZERO_ERROR; UCalendar* cal; cloner* ptr; double startMs, targetMs; ERL_NIF_TERM head, tail, out; unsigned int count; char value[ATOM_LEN]; int parsed_value; UCalendarDateFields field; struct { int enable; ERL_NIF_TERM atom; int32_t amount; } fields[UCAL_FIELD_COUNT]; if(!((argc == 4) && enif_get_resource(env, argv[0], calendar_type, (void**) &ptr) && enif_get_double(env, argv[1], &startMs) && enif_get_double(env, argv[2], &targetMs) && enif_get_list_length(env, argv[3], &count))) { return enif_make_badarg(env); } cal = (UCalendar*) cloner_get(ptr); CHECK_RES(env, cal); ucal_setMillis(cal, (UDate) startMs, &status); CHECK(env, status); for (int i = 0; i < UCAL_FIELD_COUNT; i++) fields[i].enable = 0; tail = argv[3]; while (enif_get_list_cell(env, tail, &head, &tail)) { /* Set an attribute start */ if (!enif_get_atom(env, head, (char*) value, ATOM_LEN, ERL_NIF_LATIN1)) { status = U_ILLEGAL_ARGUMENT_ERROR; CHECK(env, status); } parsed_value = parseCalendarDateField(value); if (parsed_value == -1) { status = U_ILLEGAL_ARGUMENT_ERROR; CHECK(env, status); } field = (UCalendarDateFields) parsed_value; fields[field].enable = 1; fields[field].atom = head; /* Set an attribute end */ } for (int i = 0; i < UCAL_FIELD_COUNT; i++) { if (fields[i].enable) { field = (UCalendarDateFields) i; fields[i].amount = (int) dateFieldDifference(cal, targetMs, field, status); CHECK(env, status); } } out = enif_make_list(env, 0); for (int i = UCAL_FIELD_COUNT; i; ) { i--; if (fields[i].enable) out = enif_make_list_cell(env, enif_make_tuple2(env, fields[i].atom, enif_make_int(env, fields[i].amount) ), out); } return out; }
ERL_NIF_TERM date_diff_fields(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { UErrorCode status = U_ZERO_ERROR; UCalendar* cal; cloner* ptr; double startMs, targetMs; ERL_NIF_TERM head, tail, out; unsigned int count; char value[ATOM_LEN]; int parsed_value, pos; UCalendarDateFields field; struct { int enable; ERL_NIF_TERM atom; int32_t amount; /* //} fields[POS_MAX]; Allocate more memory, but we will use only POS_MAX elems. */ } fields[UCAL_FIELD_COUNT]; if(!((argc == 4) && enif_get_resource(env, argv[0], calendar_type, (void**) &ptr) && enif_get_double(env, argv[1], &startMs) && enif_get_double(env, argv[2], &targetMs) && enif_get_list_length(env, argv[3], &count))) { return enif_make_badarg(env); } cal = (UCalendar*) cloner_get(ptr); CHECK_RES(env, cal); ucal_setMillis(cal, (UDate) startMs, &status); CHECK(env, status); for (int i = 0; i < UCAL_FIELD_COUNT; i++) fields[i].enable = 0; tail = argv[3]; while (enif_get_list_cell(env, tail, &head, &tail)) { /* Set an attribute start */ if (!enif_get_atom(env, head, (char*) value, ATOM_LEN, ERL_NIF_LATIN1)) { return enif_make_badarg(env); } parsed_value = parseCalendarDateField(value); if (parsed_value == -1) { return enif_make_badarg(env); } field = (UCalendarDateFields) parsed_value; /* Define the position in the sorted array */ pos = field_to_pos[field]; /* Unsupported type */ if (pos == -1) return enif_make_badarg(env); fields[pos].enable = 1; fields[pos].atom = head; /* Set an attribute end */ } for (int i = 0; i < POS_MAX; i++) { if (fields[i].enable) { /* Retrive the 'real' type */ field = (UCalendarDateFields) pos_to_field[i]; fields[i].amount = (int) dateFieldDifference(cal, (UDate) targetMs, field, status); CHECK(env, status); } } out = enif_make_list(env, 0); for (int i = POS_MAX; i; ) { i--; if (fields[i].enable) out = enif_make_list_cell(env, enif_make_tuple2(env, fields[i].atom, enif_make_int(env, fields[i].amount) ), out); } return out; }