static ERL_NIF_TERM do_date_get_field(ErlNifEnv* env, UCalendar* cal, const ERL_NIF_TERM field_atom, UErrorCode& status) { char value[ATOM_LEN]; int parsed_value, amount; UCalendarDateFields field; if (!enif_get_atom(env, field_atom, (char*) value, ATOM_LEN, ERL_NIF_LATIN1)) { status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } parsed_value = parseCalendarDateField(value); if (parsed_value == -1) { status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } field = (UCalendarDateFields) parsed_value; amount = (int) ucal_get(cal, field, &status); if (U_FAILURE(status)) return 0; if (field == UCAL_MONTH) amount++; /* month from 0 */ return enif_make_int(env, amount); }
inline static ERL_NIF_TERM do_offset(ErlNifEnv* env, UCalendar* cal, date_fun_ptr fun, const ERL_NIF_TERM in) { UCalendarDateFields field; UErrorCode status = U_ZERO_ERROR; ERL_NIF_TERM head, tail; ERL_NIF_TERM* tuple; unsigned int count, i; int32_t len, offset; char value[ATOM_LEN]; int parsed_value; i = 0; if (!enif_get_list_length(env, in, &count)) return enif_make_badarg(env); tail = in; while (enif_get_list_cell(env, tail, &head, &tail)) { if (enif_get_tuple(env, head, &len, (const ERL_NIF_TERM**) &tuple) && (len == 2)) { /* Set an attribute start */ if (!(enif_get_atom(env, tuple[0], (char*) value, ATOM_LEN, ERL_NIF_LATIN1) && enif_get_int(env, tuple[1], &offset))) goto bad_elem; parsed_value = parseCalendarDateField(value); if ((parsed_value == -1)) goto bad_elem; field = (UCalendarDateFields) parsed_value; fun(cal, field, offset, &status); if (U_FAILURE(status)) goto bad_elem; /* Set an attribute end */ } else goto bad_elem; } return calendar_to_double(env, (const UCalendar*) cal); bad_elem: return list_element_error(env, in, i); }
ERL_NIF_TERM date_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { UErrorCode status = U_ZERO_ERROR; UCalendar* cal; cloner* ptr; double date; UCalendarDateFields field; ERL_NIF_TERM head, tail; unsigned int count, i = 0; char value[ATOM_LEN]; int parsed_value; if(!((argc == 3) && enif_get_resource(env, argv[0], calendar_type, (void**) &ptr) && enif_get_double(env, argv[1], &date) && enif_get_list_length(env, argv[2], &count))) { return enif_make_badarg(env); } cal = (UCalendar*) cloner_get(ptr); CHECK_RES(env, cal); ucal_setMillis(cal, (UDate) date, &status); CHECK(env, status); tail = argv[2]; 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)) goto bad_elem; parsed_value = parseCalendarDateField(value); if ((parsed_value == -1)) goto bad_elem; field = (UCalendarDateFields) parsed_value; ucal_clearField(cal, field); if (U_FAILURE(status)) goto bad_elem; /* Set an attribute end */ } return calendar_to_double(env, (const UCalendar*) cal); bad_elem: return list_element_error(env, argv[2], i); }
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; }