/* * Returns the unit to which an identifier maps in a particular unit-system. * * Arguments: * systemMap NULL or pointer to the system-map. If NULL, then * NULL will be returned. * system Pointer to the unit-system. * id Pointer to the identifier. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "system" is NULL or "id" is NULL. * else Pointer to the unit in "system" with the identifier "id". * Should be passed to ut_free() when no longer needed. */ static ut_unit* getUnitById( const SystemMap* const systemMap, const ut_system* const system, const char* const id) { ut_unit* unit = NULL; /* failure */ if (system == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL unit-system argument"); } else if (id == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL identifier argument"); } else if (systemMap != NULL) { IdToUnitMap** const idToUnit = (IdToUnitMap**)smFind(systemMap, system); if (idToUnit != NULL) { const UnitAndId* uai = itumFind(*idToUnit, id); if (uai != NULL) unit = ut_clone(uai->unit); } } /* valid arguments */ return unit; }
/* * Copy a unit-structure. */ utUnit* utCopy( const utUnit *source, utUnit *dest) { return source == NULL ? NULL : dest == NULL ? NULL : resultingUnit(dest, ut_clone(source->unit2)); }
/* * Arguments: * unit The unit. May be freed upon return. * id The identifier (name or symbol). May be freed upon return. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" or "id" is NULL. * UT_OS Operating-system failure. See "errno". * else Pointer to the new unit-and-identifier. */ UnitAndId* uaiNew( const ut_unit* const unit, const char* const id) { UnitAndId* entry = NULL; /* failure */ if (id == NULL || unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("uaiNew(): NULL argument"); } else { entry = malloc(sizeof(UnitAndId)); if (entry == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't allocate %lu-byte data-structure", sizeof(UnitAndId)); } else { entry->id = strdup(id); if (entry->id == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't duplicate identifier"); } else { entry->unit = ut_clone(unit); if (entry->unit == NULL) { assert(ut_get_status() != UT_SUCCESS); free(entry->id); } } if (ut_get_status() != UT_SUCCESS) { free(entry); entry = NULL; } } } return entry; }
/*======================================================================================== * Turns the passed value into a Y/M/D date */ int utCalendar2_cal( double val, ut_unit *dataunits, int *year, int *month, int *day, int *hour, int *minute, double *second, const char *calendar_name ) { int jdnew, ndinc, ierr, iorig, iround; double fdays, extra_seconds, tot_extra_seconds; int ndays; calcalcs_cal *cal2use; /* Following vars are saved between invocations and reused if the * passed units are the same as last time. */ static ut_unit *prev_units=NULL; static cv_converter *conv_user_units_to_days=NULL; static int y0, mon0, d0, h0, min0, jday0; static double s0, extra_seconds0; static char *prev_calendar=NULL; if( dataunits == NULL ) { fprintf( stderr, "Error, utCalendar2 passed a NULL units\n" ); return( UT_ENOINIT ); } if( have_initted == 0 ) initialize( ut_get_system(dataunits) ); /* Get the calendar we will be using, based on the passed name */ cal2use = getcal( calendar_name ); if( cal2use == NULL ) { unknown_cal_emit_warning( calendar_name ); cal2use = getcal( "Standard" ); } /* See if we are being passed the same units and calendar as last time. If so, * we can optimize by not recomputing all this junk */ if( (prev_units != NULL) && (prev_calendar != NULL) && (strcmp(prev_calendar,cal2use->name)==0) && (ut_compare( prev_units, dataunits ) == 0)) { /* Units and calendar are same as used last call */ } else { /* Units/calendar combo are different from previously saved units, must redo calcs */ if( prev_units != NULL ) ut_free( prev_units ); if( prev_calendar != NULL ) free( prev_calendar ); /* Get origin day of the data units */ get_origin( dataunits, &y0, &mon0, &d0, &h0, &min0, &s0 ); /* Note: static vars */ /* Number of seconds into the specified origin day */ extra_seconds0 = h0*3600.0 + min0*60.0 + s0; /* Note: static vars */ /* Convert the origin day to Julian Day number in the specified calendar */ if( (ierr = ccs_date2jday( cal2use, y0, mon0, d0, &jday0 )) != 0 ) { fprintf( stderr, "Error in utCalendar2: %s\n", ccs_err_str(ierr) ); return( UT_EINVALID ); } /* Get converter from user-specified units to "days" */ if( conv_user_units_to_days != NULL ) cv_free( conv_user_units_to_days ); conv_user_units_to_days = get_user_to_day_converter( dataunits, y0, mon0, d0, h0, min0, s0 ); /* Save these units so we can reuse our time-consuming * calculations next time if they are the same units */ prev_units = ut_clone( dataunits ); if( ut_compare( prev_units, dataunits ) != 0 ) { fprintf( stderr, "error, internal error in udunits2 library found in routine utCalendar2: a clone of the user's units does not equal the original units!\n" ); exit(-1); } prev_calendar = (char *)malloc( sizeof(char) * (strlen(cal2use->name)+1 )); strcpy( prev_calendar, cal2use->name ); } /* Convert user value of offset to floating point days */ fdays = cv_convert_double( conv_user_units_to_days, val ); /* Get integer number of days and seconds past that */ ndays = fdays; extra_seconds = (fdays - ndays)*86400.0; /* Get new Julian day */ jdnew = jday0 + ndays; /* Handle the sub-day part */ tot_extra_seconds = extra_seconds0 + extra_seconds; ndinc = tot_extra_seconds / 86400.0; jdnew += ndinc; tot_extra_seconds -= ndinc*86400.0; if( tot_extra_seconds < 0.0 ) { tot_extra_seconds += 86400.0; jdnew--; } /* Convert to a date */ if( (ierr = ccs_jday2date( cal2use, jdnew, year, month, day )) != 0 ) { fprintf( stderr, "Error in utCalendar2: %s\n", ccs_err_str(ierr) ); return( UT_EINVALID ); } *hour = tot_extra_seconds / 3600.0; tot_extra_seconds -= *hour * 3600.0; *minute = tot_extra_seconds / 60.0; tot_extra_seconds -= *minute * 60.0; *second = tot_extra_seconds; /* Handle the rouding issues */ iorig = *second; /* Integer conversion */ iround = *second + sec_rounding_value; if( iround > iorig ) { /* printf( "rounding alg invoked, orig date: %04d-%02d-%02d %02d:%02d:%.20lf\n", *year, *month, *day, *hour, *minute, *second ); */ *second = (double)iround; if( *second >= 60.0 ) { *second -= 60.0; *minute += 1.0; if( *minute >= 60.0 ) { *minute -= 60.0; *hour += 1.0; if( *hour >= 24.0 ) { *hour -= 24.0; if( (ierr = ccs_jday2date( cal2use, jdnew+1, year, month, day )) != 0 ) { fprintf( stderr, "Error in utCalendar2: %s\n", ccs_err_str(ierr) ); return( UT_EINVALID ); } } } } /* printf( "after rounding alg here is new date: %04d-%02d-%02d %02d:%02d:%02.20lf\n", *year, *month, *day, *hour, *minute, *second ); */ } return(0); }
/*======================================================================================== * Turn the passed Y/M/D date into a value in the user's units */ int utInvCalendar2_cal( int year, int month, int day, int hour, int minute, double second, ut_unit *user_unit, double *value, const char *calendar_name ) { int jday, ierr, diff_in_days; double fdiff_in_days, val_days, val_partdays, fdiff_in_partdays, fpartday; calcalcs_cal *cal2use; /* Following vars are static and retained between invocations for efficiency */ static ut_unit *prev_units=NULL; static int y0, mon0, d0, h0, min0, jday0; static double s0, fpartday0; static cv_converter *conv_days_to_user_units=NULL; static char *prev_calendar=NULL; if( have_initted == 0 ) initialize( ut_get_system(user_unit) ); /* Get the calendar we will be using, based on the passed name */ cal2use = getcal( calendar_name ); if( cal2use == NULL ) { unknown_cal_emit_warning( calendar_name ); cal2use = getcal( "Standard" ); } if( (prev_units != NULL) && (prev_calendar != NULL) && (strcmp(prev_calendar,cal2use->name)==0) && (ut_compare( prev_units, user_unit ) == 0)) { /* Units are same as used last call */ } else { if( prev_units != NULL ) ut_free( prev_units ); if( prev_calendar != NULL ) free( prev_calendar ); if( conv_days_to_user_units != NULL ) cv_free( conv_days_to_user_units ); /* Get origin day of the data units */ get_origin( user_unit, &y0, &mon0, &d0, &h0, &min0, &s0 ); /* Note: static vars */ /* Convert the origin day to Julian Day number in the specified calendar */ if( (ierr = ccs_date2jday( cal2use, y0, mon0, d0, &jday0 )) != 0 ) { fprintf( stderr, "Error in utCalendar2: %s\n", ccs_err_str(ierr) ); return( UT_EINVALID ); } /* Get the origin's HMS in fractional (floating point) part of a Julian day */ fpartday0 = (double)h0/24.0 + (double)min0/1440.0 + s0/86400.0; /* Get converter for turning days into user's units */ conv_days_to_user_units = get_day_to_user_converter( user_unit, y0, mon0, d0, h0, min0, s0 ); /* Save these units so we can reuse our time-consuming * calculations next time if they are the same units */ prev_units = ut_clone( user_unit ); if( ut_compare( prev_units, user_unit ) != 0 ) { fprintf( stderr, "error, internal error in udunits2 library found in routine utInvCalendar2: a clone of the user's units does not equal the original units!\n" ); exit(-1); } prev_calendar = (char *)malloc( sizeof(char) * (strlen(cal2use->name)+1 )); strcpy( prev_calendar, cal2use->name ); } /* Turn passed date into a Julian day */ if( (ierr = ccs_date2jday( cal2use, year, month, day, &jday )) != 0 ) { fprintf( stderr, "Error in utInvCalendar2: %s\n", ccs_err_str(ierr) ); return( UT_EINVALID ); } /* jday and jday0 can be very large and nearly equal, so we difference * them first to keep the precision high */ diff_in_days = jday - jday0; fdiff_in_days = (double)diff_in_days; /* Get the fractional (floating point) part of a Julian day difference */ fpartday = (double)hour/24.0 + (double)minute/1440.0 + second/86400.0; fdiff_in_partdays = fpartday - fpartday0; /* Convert days and partial days to user's units */ val_days = cv_convert_double( conv_days_to_user_units, fdiff_in_days ); val_partdays = cv_convert_double( conv_days_to_user_units, fdiff_in_partdays ); /* Hopefully this will minimize the roundoff errors */ *value = val_days + val_partdays; return(0); }
/*! * Constructs a copy of \a other. */ UdUnit::UdUnit(const UdUnit &other): m_errorStatus(other.m_errorStatus), m_type(NullUnit) { m_unit = ut_clone(other.m_unit); }