/******************************************************************//** Frees a block from a memory heap. */ UNIV_INTERN void mem_heap_block_free( /*================*/ mem_heap_t* heap, /*!< in: heap */ mem_block_t* block) /*!< in: block to free */ { ulint type; ulint len; #ifndef UNIV_HOTBACKUP buf_block_t* buf_block = block->buf_block; #endif /* !UNIV_HOTBACKUP */ if (block->magic_n != MEM_BLOCK_MAGIC_N) { mem_analyze_corruption(block); } UT_LIST_REMOVE(list, heap->base, block); #ifdef MEM_PERIODIC_CHECK mem_pool_mutex_enter(); UT_LIST_REMOVE(mem_block_list, mem_block_list, block); mem_pool_mutex_exit(); #endif ut_ad(heap->total_size >= block->len); heap->total_size -= block->len; type = heap->type; len = block->len; block->magic_n = MEM_FREED_BLOCK_MAGIC_N; #ifndef UNIV_HOTBACKUP if (!srv_use_sys_malloc) { #ifdef UNIV_MEM_DEBUG /* In the debug version we set the memory to a random combination of hex 0xDE and 0xAD. */ mem_erase_buf((byte*)block, len); #else /* UNIV_MEM_DEBUG */ UNIV_MEM_ASSERT_AND_FREE(block, len); #endif /* UNIV_MEM_DEBUG */ } if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) { ut_ad(!buf_block); mem_area_free(block, mem_comm_pool); } else { ut_ad(type & MEM_HEAP_BUFFER); buf_block_free(buf_block); } #else /* !UNIV_HOTBACKUP */ #ifdef UNIV_MEM_DEBUG /* In the debug version we set the memory to a random combination of hex 0xDE and 0xAD. */ mem_erase_buf((byte*)block, len); #else /* UNIV_MEM_DEBUG */ UNIV_MEM_ASSERT_AND_FREE(block, len); #endif /* UNIV_MEM_DEBUG */ ut_free(block); #endif /* !UNIV_HOTBACKUP */ }
void mem_area_free( /*==========*/ void* ptr, /* in, own: pointer to allocated memory buffer */ mem_pool_t* pool) /* in: memory pool */ { mem_area_t* area; mem_area_t* buddy; void* new_ptr; ulint size; ulint n; /* It may be that the area was really allocated from the OS with regular malloc: check if ptr points within our memory pool */ if ((byte*)ptr < pool->buf || (byte*)ptr >= pool->buf + pool->size) { ut_free(ptr); return; } area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE); if (mem_area_get_free(area)) { fprintf(stderr, "InnoDB: Error: Freeing element to mem pool" " free list though the\n" "InnoDB: element is marked free!\n"); mem_analyze_corruption(area); ut_error; } size = mem_area_get_size(area); UNIV_MEM_FREE(ptr, size - MEM_AREA_EXTRA_SIZE); if (size == 0) { fprintf(stderr, "InnoDB: Error: Mem area size is 0. Possibly a" " memory overrun of the\n" "InnoDB: previous allocated area!\n"); mem_analyze_corruption(area); ut_error; } #ifdef UNIV_LIGHT_MEM_DEBUG if (((byte*)area) + size < pool->buf + pool->size) { ulint next_size; next_size = mem_area_get_size( (mem_area_t*)(((byte*)area) + size)); if (ut_2_power_up(next_size) != next_size) { fprintf(stderr, "InnoDB: Error: Memory area size %lu," " next area size %lu not a power of 2!\n" "InnoDB: Possibly a memory overrun of" " the buffer being freed here.\n", (ulong) size, (ulong) next_size); mem_analyze_corruption(area); ut_error; } } #endif buddy = mem_area_get_buddy(area, size, pool); n = ut_2_log(size); mutex_enter(&(pool->mutex)); mem_n_threads_inside++; ut_a(mem_n_threads_inside == 1); if (buddy && mem_area_get_free(buddy) && (size == mem_area_get_size(buddy))) { /* The buddy is in a free list */ if ((byte*)buddy < (byte*)area) { new_ptr = ((byte*)buddy) + MEM_AREA_EXTRA_SIZE; mem_area_set_size(buddy, 2 * size); mem_area_set_free(buddy, FALSE); } else { new_ptr = ptr; mem_area_set_size(area, 2 * size); } /* Remove the buddy from its free list and merge it to area */ UT_LIST_REMOVE(free_list, pool->free_list[n], buddy); pool->reserved += ut_2_exp(n); mem_n_threads_inside--; mutex_exit(&(pool->mutex)); mem_area_free(new_ptr, pool); return; } else { UT_LIST_ADD_FIRST(free_list, pool->free_list[n], area); mem_area_set_free(area, TRUE); ut_ad(pool->reserved >= size); pool->reserved -= size; } mem_n_threads_inside--; mutex_exit(&(pool->mutex)); ut_ad(mem_pool_validate(pool)); }
// CONSTRUCTOR DPC_UnitConvDataStream::DPC_UnitConvDataStream(DataStream* ds, const char *ToUnits, const char *FromUnitsHint ) { ut_unit * to = NULL ; ut_unit * from = NULL ; const char * recorded_units = ds->getUnit().c_str(); source_ds = ds; if (ToUnits != NULL) { to = ut_parse(u_system, ToUnits, UT_ASCII) ; to_units = ToUnits ; } // If the user has specified a units conversion and those units are valid ... if ( to != NULL ) { // If the recorded data file doesn't contain the units in which the data is recorded ... if ((recorded_units == NULL) || (strcmp(recorded_units,"") == 0)) { // If the user didn't give us a hint as to what the units are (using var@from_units) ... if ((FromUnitsHint == NULL) || (strcmp(FromUnitsHint,"") == 0)) { // set the from units to the same as the to units. cf = cv_get_trivial() ; std::cerr << "ERROR: Unable to to perform units conversion" << " because the recorded data doesn't indicate it's" << " units and no @from_units hint is provided." << std::endl; std::cerr.flush(); } else { // the user did give us a hint. from = ut_parse(u_system, FromUnitsHint, UT_ASCII) ; if ( ! from ) { std::cerr << "ERROR: Unable to to perform units conversion" << " because the recorded data doesn't indicate it's" << " units and although a @from_units hint is provided (" << "(\"" << FromUnitsHint << "\"), they are invalid." << std::endl; std::cerr.flush(); } } } else { // the recorded data file does "know" the units in which the data was recorded, // so those will be the units that we convert from. from = ut_parse(u_system, recorded_units, UT_ASCII) ; if ( !from ) { std::cerr << "ERROR: Unable to to perform units conversion because the" << " units in the data recording file appear to be corrupt." << std::endl; std::cerr.flush(); } } // If we know what units the data was recorded in ... if ( from != NULL ) { cf = ut_get_converter(from,to) ; if ( cf == NULL ) { std::cerr << "ERROR: Unable to convert from \"" << FromUnitsHint << "\" to \"" << to_units << "\" because they are incompatible." << std::endl; std::cerr.flush(); cf = cv_get_trivial() ; } } else { std::cerr << "ERROR: Unable to perform units conversion becuase the units" << " that the data is recorded in is unknown." << std::endl; cf = cv_get_trivial() ; } } else { // The user has not specified a units conversion or the units were not valid. // If the recorded data file doesn't contain the units in which the data is recorded ... if ((recorded_units == NULL) || (strcmp(recorded_units,"") == 0)) { // If the user didn't give us a hint as to what the units are (using var@from_units) ... if ((FromUnitsHint == NULL) || (strcmp(FromUnitsHint,"") == 0)) { cf = cv_get_trivial() ; } else { // the user did give us a hint. to_units = FromUnitsHint ; cf = cv_get_trivial() ; } } else { // the recorded data file does "know" the units in which the data was recorded, to_units = recorded_units ; cf = cv_get_trivial() ; } } if (to) ut_free(to) ; if (from) ut_free(from) ; this->begin(); }
void FieldDescription::parseComment(std::string comment) { std::string ret_str ; bool units_found = false ; bool io_found = false ; bool chkpnt_io_found = false ; unsigned int chkpnt_io ; if ( comment.empty() ) { // If the comment is empty default all I/O enabled. io = 15 ; return ; } if ( debug_level >= 5 ) { std::cout << "comment before " << comment << std::endl ; } // remove open comment chars comment = get_regex_field(comment , "^(//|/\\*)(.*)" , 2) ; //std::cout << "1. " << comment << std::endl ; // remove optional doxygen comment chars // Note: I had to use [ \t\n\r] for \s because the Mac don't understand! comment = get_regex_field(comment , "^((\\*|!)<)?[ \t\n\r]*(.*)" , 3) ; //std::cout << "2. " << comment << std::endl ; // remove optional doxygen keyword comment = get_regex_field(comment , "(\\\\\\w+[ \t\n\r]*)?(.*)" , 2) ; //std::cout << "3. " << comment << std::endl ; ret_str = get_regex_field(comment , "@?trick_chkpnt_io[\\({]([^\\)}]+)[\\)}]" , 1) ; if ( ! ret_str.empty()) { chkpnt_io = io_map[ret_str] ; //std::cout << "go for trick_chkpnt_io " << io << std::endl ; chkpnt_io_found = true ; comment = get_regex_field(comment , "(.*)@?trick_chkpnt_io[\\({]([^\\)}]+)[\\)}]" , 1) + get_regex_field(comment , "@?trick_chkpnt_io[\\({]([^\\)}]+)[\\)}](.*)" , 2) ; } ret_str = get_regex_field(comment , "@?trick_io[\\({]([^\\)}]+)[\\)}]" , 1) ; if ( ! ret_str.empty()) { io = io_map[ret_str] ; //std::cout << "go for trick_io " << io << std::endl ; io_found = true ; comment = get_regex_field(comment , "(.*)@?trick_io[\\({]([^\\)}]+)[\\)}]" , 1) + get_regex_field(comment , "@?trick_io[\\({]([^\\)}]+)[\\)}](.*)" , 2) ; } /* Units can include parenthesis now. We need to match the parenthesis in trick_units() to get the whole units string. */ std::size_t tu_string = comment.find("trick_units") ; if ( tu_string != std::string::npos ) { std::size_t ustart = tu_string + std::string("trick_units").length() ; std::size_t uend = ustart + 1 ; std::stack<char> parens ; parens.push( comment[ustart]); while ( ! parens.empty() and (uend < comment.length())) { switch ( comment[uend] ) { case '(': parens.push('(') ; break ; case ')': if (parens.top() == '(') { parens.pop() ; } break ; case '}': if (parens.top() == '{') { parens.pop() ; } break ; } uend++ ; } if ( parens.empty() ) { units = comment.substr(ustart + 1 , uend - ustart - 2) ; units_found = true ; // If we have "@trick_units" include the "@" sign for erasure. if ( tu_string > 0 and comment[tu_string-1] == '@' ) { tu_string -= 1 ; } comment.erase(tu_string , uend - tu_string) ; } else { std::cout << "unmatched parenthesis for trick_units" << std::endl ; } } if ( ! io_found ) { // Note: I had to use [ \t\n\r] for \s because the Mac don't understand! ret_str = get_regex_field(comment , "^[ \t\n\r]*(\\*io|\\*oi|\\*i|\\*o|\\*\\*)" , 1) ; //std::cout << "3. " << ret_str << std::endl ; if ( ! ret_str.empty()) { io = io_map[ret_str] ; //std::cout << "stand-alone io " << io << std::endl ; io_found = true ; comment = get_regex_field(comment , "^[ \t\n\r]*(\\*io|\\*oi|\\*i|\\*o|\\*\\*)[ \t\n\r]*(.*)" , 2) ; } } //std::cout << "3. " << comment << std::endl ; if ( ! units_found ) { ret_str = get_regex_field(comment , "^[ \t\n\r]*\\(([^\\)]*)\\)" , 1) ; if ( ! ret_str.empty()) { units = ret_str ; //std::cout << "stand-alone units " << units << std::endl ; units_found = true ; comment = get_regex_field(comment , "^[ \t\n\r]*\\(([^\\)]*)\\)(.*)" , 2) ; } else { ret_str = get_regex_field(comment , "^[ \t\n\r]*([^ \t\n\r)]*)" , 1) ; if ( ! ret_str.empty()) { units = ret_str ; //std::cout << "stand-alone units " << units << " " << comment << std::endl ; units_found = true ; comment = get_regex_field(comment , "^[ \t\n\r]*([^ \t\n\r)]*)(.*)" , 2) ; } } } // Test if we have valid units. We need to have found a units string and an io spec not zero // Possible todo is to create a map of valid units so we don't have to retest each string. if ( units_found and io != 0 and (valid_units.find(units) == valid_units.end())) { // remove spaces units.erase(remove_if(units.begin(), units.end(), isspace), units.end()); if ( !units.compare("--") ) { units = "1" ; } else { // map old unit names to new names std::string new_units = map_trick_units_to_udunits(units) ; if ( units.compare(new_units) ) { if ( ! units_truth_is_scary ) { std::cout << "\033[33mUnits converted from [" << units << "] to [" << new_units << "] " << file_name << ":" << line_no << "\033[0m" << std::endl ; } units = new_units ; } ut_unit * test_units = ut_parse(u_system, units.c_str() , UT_ASCII) ; if ( test_units == NULL ) { // If the units are invalid write an error message and change the units to "1" std::cout << "\033[31mBad units specification [" << units << "] " << file_name << ":" << line_no << "\033[0m" << std::endl ; units = "1" ; } else { // If the units are valid, free the memory allocated by new_units. ut_free(test_units) ; valid_units.insert(units) ; } } } if ( io == 4 ) { std::cout << "\033[33mWarning: " << file_name << ": line " << line_no << ": " << "\"--\" is not a valid trick_io value. Setting to *io (3)\033[0m" << std::endl ; io = 3 ; } if ( chkpnt_io_found == true ) { // If a checkpoint I/O spec is found add it to the io field. io |= (chkpnt_io << 2 ) ; } else { // else duplicated the io field to the chkpnt io field. io |= (io << 2 ) ; } // The rest of the comment is the description of the variable. // remove the c comment end marker. comment = get_regex_field(comment , "(.*)\\*/" , 1) ; // posix c regular expressions are terrible. the regexes above will leave "@" signs because // the regular expressions are so greedy. comment = get_regex_field(comment , "^[ \t\n\r@]+(.*)" , 1) ; // remove leading and trailing whitespace comment = trim(comment) ; // escape special characters, convert tabs and newlines to spaces, remove multiple spaces. std::ostringstream ss ; bool is_space = false ; for (std::string::iterator it = comment.begin(); it != comment.end(); it++) { switch (*it) { case '\\': ss << "\\\\"; is_space = false ; break; case '"': ss << "\\\""; is_space = false ; break; case '\b': ss << "\\b"; is_space = false ; break; case '\f': ss << "\\f"; is_space = false ; break; case '\n': case '\r': case '\t': case ' ': if ( ! is_space ) ss << " "; is_space = true ; break; default: ss << *it; is_space = false ; break; } } description = ss.str() ; }
static int handleRequest(void) { int success = 0; if (getInputValue()) { if (getOutputRequest()) { if (_wantDefinition) { char buf[256]; ut_unit* unit = ut_scale(_haveUnitAmount, _haveUnit); int nbytes = ut_format(unit, buf, sizeof(buf), _formattingOptions); if (nbytes >= sizeof(buf)) { errMsg("Resulting unit specification is too long"); } else if (nbytes >= 0) { buf[nbytes] = 0; (void)printf(" %s\n", buf); } ut_free(unit); } else if (!ut_are_convertible(_wantUnit, _haveUnit)) { errMsg("Units are not convertible"); } else { cv_converter* conv = ut_get_converter(_haveUnit, _wantUnit); if (conv == NULL) { errMsg("Couldn't get unit converter"); } else { char haveExp[_POSIX_MAX_INPUT+1]; char exp[_POSIX_MAX_INPUT+1]; char whiteSpace[] = " \t\n\r\f\v\xa0"; int needsParens = strpbrk(_wantSpec, whiteSpace) != NULL; int n; (void)printf( needsParens ? " %g %s = %g (%s)\n" : " %g %s = %g %s\n", _haveUnitAmount, _haveUnitSpec, cv_convert_double(conv, _haveUnitAmount), _wantSpec); (void)sprintf(haveExp, strpbrk(_haveUnitSpec, whiteSpace) || strpbrk(_haveUnitSpec, "/") ? "(x/(%s))" : "(x/%s)", _haveUnitSpec); n = cv_get_expression(conv, exp, sizeof(exp), haveExp); if (n >= 0) (void)printf( strpbrk(_wantSpec, whiteSpace) || strpbrk(_wantSpec, "/") ? " x/(%s) = %*s\n" : " x/%s = %*s\n", _wantSpec, n, exp); cv_free(conv); } } success = 1; } } return success; }
int /* [rcd] Return code */ nco_cln_sng_rbs /* [fnc] Rebase calendar string for legibility */ (const ptr_unn val, /* I [sct] Value to rebase */ const long val_idx, /* I [idx] Index into 1-D array of values */ const nc_type val_typ, /* I [enm] Value type */ const char *unit_sng, /* I [sng] Units string */ char *lgb_sng) /* O [sng] Legible version of input string */ { /* Purpose: Rebase calendar string for legibility Assumptions: Input units string unit_sng is a calendar date, i.e., contains "from", "since", or "after" ncdump handles this in nctime0.c dumplib.c/nctime_val_tostring() by Dave Allured, NOAA cdRel2Iso() from CDMS by Bob Drach, LLNL cdParseRelunits() from CDMS by Bob Drach, LLNL */ #ifdef HAVE_UDUNITS2_H const char fnc_nm[]="nco_cln_sng_rbs()"; /* [sng] Function name */ double val_dbl; /* [day] Calendar offset converted to double */ int ut_rcd; /* [enm] UDUnits2 status */ ut_system *ut_sys; ut_unit *ut_sct_in; /* [sct] UDUnits structure, input units */ ut_unit *ut_sct_out; /* [sct] UDUnits structure, output units */ /* Quick return if units DNE */ if(!unit_sng) return NCO_NOERR; /* When empty, ut_read_xml() uses environment variable UDUNITS2_XML_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ if(nco_dbg_lvl_get() >= nco_dbg_vrb) ut_set_error_message_handler(ut_write_to_stderr); else ut_set_error_message_handler(ut_ignore); ut_sys=ut_read_xml(NULL); if(!ut_sys){ (void)fprintf(stdout,"%s: %s() failed to initialize UDUnits2 library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; /* Failure */ } /* end if err */ /* Units string containing calendar origin converted to UDUnit structure */ ut_sct_in=ut_parse(ut_sys,unit_sng,UT_ASCII); if(!ut_sct_in){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",unit_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",unit_sng); return NCO_ERR; /* Failure */ } /* endif coordinate on disk has no units attribute */ /* Convert time since calendar origin to double */ val_dbl=ptr_unn_2_scl_dbl(val,val_typ); /* Units string to convert to */ ut_sct_out=ut_offset(ut_sct_in,val_dbl); if(!ut_sct_out){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: Empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",unit_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",unit_sng); return NCO_ERR; /* Failure */ } /* endif */ val_dbl+=0*val_idx; /* CEWI */ ut_free(ut_sct_in); ut_free(ut_sct_out); ut_free_system(ut_sys); /* Free memory taken by UDUnits library */ #endif /* !HAVE_UDUNITS2 */ lgb_sng[0]='\0'; /* CEWI */ return NCO_NOERR; } /* end nco_cln_sng_rbs() */
int /* [rcd] Return code */ nco_cln_clc_dff /* [fnc] UDUnits2 Compute difference between two coordinate units */ (const char *fl_unt_sng, /* I [ptr] units attribute string from disk */ const char *fl_bs_sng, /* I [ptr] units attribute string from disk */ double crr_val, double *og_val) /* O [] Difference between two units strings */ { const char fnc_nm[]="nco_cln_clc_dff()"; /* [sng] Function name */ cv_converter *ut_cnv; /* UDUnits converter */ int ut_rcd; /* [enm] UDUnits2 status */ ut_system *ut_sys; ut_unit *ut_sct_in; /* [sct] UDUnits structure, input units */ ut_unit *ut_sct_out; /* [sct] UDUnits structure, output units */ /* Quick return if units identical */ if(!strcasecmp(fl_unt_sng,fl_bs_sng)){ *og_val=crr_val; return NCO_NOERR; } /* end if */ /* When empty, ut_read_xml() uses environment variable UDUNITS2_XML_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ if(nco_dbg_lvl_get() >= nco_dbg_vrb) ut_set_error_message_handler(ut_write_to_stderr); else ut_set_error_message_handler(ut_ignore); ut_sys=ut_read_xml(NULL); if(ut_sys == NULL){ (void)fprintf(stdout,"%s: %s() failed to initialize UDUnits2 library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; /* Failure */ } /* end if err */ /* Units string to convert from */ ut_sct_in=ut_parse(ut_sys,fl_unt_sng,UT_ASCII); if(!ut_sct_in){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",fl_unt_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",fl_unt_sng); return NCO_ERR; /* Failure */ } /* endif coordinate on disk has no units attribute */ /* Units string to convert to */ ut_sct_out=ut_parse(ut_sys,fl_bs_sng,UT_ASCII); if(!ut_sct_out){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: Empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",fl_bs_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",fl_bs_sng); return NCO_ERR; /* Failure */ } /* endif */ /* Create converter */ ut_cnv=ut_get_converter(ut_sct_in,ut_sct_out); /* UDUnits converter */ if(!ut_cnv){ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"WARNING: One of units, %s or %s, is NULL\n",fl_bs_sng,fl_unt_sng); if(ut_rcd == UT_NOT_SAME_SYSTEM) (void)fprintf(stderr,"WARNING: Units %s and %s belong to different unit systems\n",fl_bs_sng,fl_unt_sng); if(ut_rcd == UT_MEANINGLESS) (void)fprintf(stderr,"WARNING: Conversion between user-specified unit \"%s\" and file units \"%s\" is meaningless\n",fl_bs_sng,fl_unt_sng); return NCO_ERR; /* Failure */ } /* endif */ /* Convert */ *og_val=cv_convert_double(ut_cnv,crr_val); if(nco_dbg_lvl_get() >= nco_dbg_var) fprintf(stderr, "%s: INFO %s() reports conversion between systems \"%s\" and \"%s\" is %f\n",nco_prg_nm_get(),fnc_nm,fl_unt_sng,fl_bs_sng,*og_val); ut_free(ut_sct_in); ut_free(ut_sct_out); cv_free(ut_cnv); ut_free_system(ut_sys); /* Free memory taken by UDUnits library */ return NCO_NOERR; } /* end UDUnits2 nco_cln_clc_dff() */
NhlErrorTypes ut_calendar_W( void ) { /* * Input array variables */ void *x; double *tmp_x; NrmQuark *sspec = NULL; char *cspec, *cspec_orig; int *option; int ndims_x; ng_size_t dsizes_x[NCL_MAX_DIMENSIONS]; int has_missing_x; NclScalar missing_x, missing_dx; NclBasicDataTypes type_x; /* * Variables for calculating fraction of year, if the option is 4. */ int doy, nsid, total_seconds_in_year, seconds_in_doy, seconds_in_hour; int seconds_in_minute; double current_seconds_in_year, fraction_of_year; /* * Variables for retrieving attributes from the first argument. */ NclAttList *attr_list; NclAtt attr_obj; NclStackEntry stack_entry; NrmQuark *scal; char *ccal = NULL; /* * Variables for Udunits package. */ ut_system *utopen_ncl(), *unit_system; ut_unit *utunit; /* * Output variables. */ int year, month, day, hour, minute; double second; void *date = NULL; int ndims_date = 0; ng_size_t *dsizes_date; NclScalar missing_date; NclBasicDataTypes type_date = NCL_none; NclObjClass type_date_t = NCL_none; /* * Variables for returning "calendar" attribute. */ int att_id; NclQuark *calendar; NclMultiDValData att_md, return_md; NclVar tmp_var; NclStackEntry return_data; /* * various */ int ret, return_missing; ng_size_t dsizes[1]; ng_size_t i, total_size_x; ng_size_t total_size_date = 0; ng_size_t index_date; int months_to_days_fix=0, years_to_days_fix=0; extern float truncf(float); /* * Before we do anything, initialize the Udunits package. */ unit_system = utopen_ncl(); /* * Retrieve parameters * * Note any of the pointer parameters can be set to NULL, which * implies you don't care about its value. */ x = (void*)NclGetArgValue( 0, 2, &ndims_x, dsizes_x, &missing_x, &has_missing_x, &type_x, DONT_CARE); /* * Get option. */ option = (int*)NclGetArgValue( 1, 2, NULL, NULL, NULL, NULL, NULL, 1); /* * The "units" attribute of "time" must be set, otherwise missing * values will be returned. * * The "calendar" option may optionally be set, but it must be equal to * one of the recognized calendars. */ return_missing = 0; stack_entry = _NclGetArg(0, 2, DONT_CARE); switch (stack_entry.kind) { case NclStk_VAR: if (stack_entry.u.data_var->var.att_id != -1) { attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id); if (attr_obj == NULL) { return_missing = 1; break; } } else { /* * att_id == -1 ==> no attributes specified; return all missing. */ return_missing = 1; break; } /* * Check for attributes. If none are specified, then return missing values. */ if (attr_obj->att.n_atts == 0) { return_missing = 1; break; } else { /* * Get list of attributes. */ attr_list = attr_obj->att.att_list; /* * Loop through attributes and check them. */ while (attr_list != NULL) { if ((strcmp(attr_list->attname, "calendar")) == 0) { scal = (NrmQuark *) attr_list->attvalue->multidval.val; ccal = NrmQuarkToString(*scal); if(strcasecmp(ccal,"standard") && strcasecmp(ccal,"gregorian") && strcasecmp(ccal,"noleap") && strcasecmp(ccal,"365_day") && strcasecmp(ccal,"365") && strcasecmp(ccal,"360_day") && strcasecmp(ccal,"360") ) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: the 'calendar' attribute is not equal to a recognized calendar. Returning all missing values."); return_missing = 1; } } if ((strcmp(attr_list->attname, "units")) == 0) { sspec = (NrmQuark *) attr_list->attvalue->multidval.val; } attr_list = attr_list->next; } } default: break; } /* * Convert sspec to character string. */ if(sspec == NULL) { NhlPError(NhlFATAL,NhlEUNKNOWN,"ut_calendar: no 'units' attribute provided"); return(NhlFATAL); } cspec = NrmQuarkToString(*sspec); /* * There's a bug in utInvCalendar2_cal that doesn't handle the * 360-day calendar correctly if units are "years since" or * "months since". * * To fix this bug, we convert these units to "days since", do the * calculation as "days since", and then convert back to the original * "years since" or "months since" requested units. */ cspec_orig = (char*)calloc(strlen(cspec)+1,sizeof(char)); strcpy(cspec_orig,cspec); cspec = fix_units_for_360_bug(ccal,cspec,&months_to_days_fix, &years_to_days_fix); /* * Make sure cspec is a valid udunits string. */ utunit = ut_parse(unit_system, cspec, UT_ASCII); if(utunit == NULL) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: Invalid specification string. Missing values will be returned."); return_missing = 1; } /* * Calculate size of input array. */ total_size_x = 1; for( i = 0; i < ndims_x; i++ ) total_size_x *= dsizes_x[i]; /* * Calculate size and dimensions for output array, and allocate * memory for output array. The output size will vary depending * on what option the user has specified. Only options -5 to 4 * are currently recognized. (option = -4 doesn't exist.) */ if(*option < -5 || *option > 4 || *option == -4) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: Unknown option, defaulting to 0."); *option = 0; } if(*option == 0) { type_date = NCL_float; type_date_t = nclTypefloatClass; total_size_date = 6 * total_size_x; missing_date = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis; ndims_date = ndims_x + 1; date = (float *)calloc(total_size_date,sizeof(float)); } else if(*option == -5) { /* identical to option=0, except returns ints */ type_date = NCL_int; type_date_t = nclTypeintClass; total_size_date = 6 * total_size_x; missing_date = ((NclTypeClass)nclTypeintClass)->type_class.default_mis; ndims_date = ndims_x + 1; date = (int *)calloc(total_size_date,sizeof(int)); } else if(*option >= 1 && *option <= 4) { type_date = NCL_double; type_date_t = nclTypedoubleClass; total_size_date = total_size_x; missing_date = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis; ndims_date = ndims_x; date = (double *)calloc(total_size_date,sizeof(double)); } else if(*option >= -3 && *option <= -1) { type_date = NCL_int; type_date_t = nclTypeintClass; total_size_date = total_size_x; missing_date = ((NclTypeClass)nclTypeintClass)->type_class.default_mis; ndims_date = ndims_x; date = (int *)calloc(total_size_date,sizeof(int)); } dsizes_date = (ng_size_t *)calloc(ndims_date,sizeof(ng_size_t)); /* * Make sure we have enough memory for output. */ if( date == NULL || dsizes_date == NULL) { NhlPError(NhlFATAL,NhlEUNKNOWN,"ut_calendar: Unable to allocate memory for output arrays"); return(NhlFATAL); } /* * Calculate output dimension sizes. */ for( i = 0; i < ndims_x; i++ ) dsizes_date[i] = dsizes_x[i]; if(*option == 0 || *option == -5) { dsizes_date[ndims_x] = 6; } /* * Coerce missing values to double. */ coerce_missing(type_x,has_missing_x,&missing_x,&missing_dx,NULL); /* * If we reach this point and return_missing is not 0, then either * "units" was invalid or wasn't set, or "calendar" was not a * recoginized calendar. We return all missing values in this case. */ if(return_missing) { if(*option == 0) { for(i = 0; i < total_size_date; i++ ) { ((float*)date)[i] = missing_date.floatval; } } else if(*option == -5) { /* identical to option=0, except returns ints */ for(i = 0; i < total_size_date; i++ ) { ((int*)date)[i] = missing_date.intval; } } else if(*option >= 1 && *option <= 4) { for(i = 0; i < total_size_date; i++ ) { ((double*)date)[i] = missing_date.doubleval; } } else if(*option >= -3 && *option <= -1) { for(i = 0; i < total_size_date; i++ ) { ((int*)date)[i] = missing_date.intval; } } /* * Return all missing values. */ ret = NclReturnValue(date,ndims_date,dsizes_date, &missing_date,type_date,0); NclFree(dsizes_date); return(ret); } /* * Convert input to double if necessary. */ tmp_x = coerce_input_double(x,type_x,total_size_x,has_missing_x,&missing_x, &missing_dx); /* * This is the bug fix for 360 day calendars and a units * of "years since" or "months since". We have to convert * from "years since" or "months since" to "days since". * * See above for more information about the bug. */ if(years_to_days_fix == 1) { for(i = 0; i < total_size_x; i++ ) tmp_x[i] *= 360.; } if(months_to_days_fix == 1) { for(i = 0; i < total_size_x; i++ ) tmp_x[i] *= 30.; } /* * Loop through each element and get the 6 values. */ index_date = 0; for( i = 0; i < total_size_x; i++ ) { if(!has_missing_x || (has_missing_x && tmp_x[i] != missing_dx.doubleval)) { (void) utCalendar2_cal(tmp_x[i],utunit,&year,&month,&day, &hour,&minute,&second,ccal); /* * Calculate the return values, based on the input option. */ switch(*option) { case 0: ((float*)date)[index_date] = (float)year; ((float*)date)[index_date+1] = (float)month; ((float*)date)[index_date+2] = (float)day; ((float*)date)[index_date+3] = (float)hour; ((float*)date)[index_date+4] = (float)minute; ((float*)date)[index_date+5] = second; break; /* identical to option=0, except returns ints */ case -5: ((int*)date)[index_date] = year; ((int*)date)[index_date+1] = month; ((int*)date)[index_date+2] = day; ((int*)date)[index_date+3] = hour; ((int*)date)[index_date+4] = minute; ((int*)date)[index_date+5] = (int)truncf(second); break; /* * YYYYMM */ case -1: ((int*)date)[index_date] = (100*year) + month; break; case 1: ((double*)date)[index_date] = (double)(100*year) + (double)month; break; /* * YYYYMMDD */ case -2: ((int*)date)[index_date] = (10000*year) + (100*month) + day; break; case 2: ((double*)date)[index_date] = (double)(10000*year) + (double)(100*month) + (double)day; break; /* * YYYYMMDDHH */ case -3: ((int*)date)[index_date] = (1000000*year) + (10000*month) + (100*day) + hour; break; case 3: ((double*)date)[index_date] = (double)(1000000*year) + (double)(10000*month) + (double)(100*day) + (double)hour; break; /* * YYYY.fraction_of_year */ case 4: nsid = 86400; /* num seconds in a day */ if(ccal == NULL) { total_seconds_in_year = seconds_in_year(year,"standard"); doy = day_of_year(year,month,day,"standard"); } else { total_seconds_in_year = seconds_in_year(year,ccal); doy = day_of_year(year,month,day,ccal); } if(doy > 1) { seconds_in_doy = (doy-1) * nsid; } else { seconds_in_doy = 0; } if(hour > 1) { seconds_in_hour = (hour-1) * 3600; } else { seconds_in_hour = 0; } if(minute > 1) { seconds_in_minute = (minute-1) * 60; } else { seconds_in_minute = 0; } current_seconds_in_year = seconds_in_doy + seconds_in_hour + seconds_in_minute + second; fraction_of_year = current_seconds_in_year/(double)total_seconds_in_year; ((double*)date)[index_date] = (double)year + fraction_of_year; break; } } else { switch(*option) { case 0: ((float*)date)[index_date] = missing_date.floatval; ((float*)date)[index_date+1] = missing_date.floatval; ((float*)date)[index_date+2] = missing_date.floatval; ((float*)date)[index_date+3] = missing_date.floatval; ((float*)date)[index_date+4] = missing_date.floatval; ((float*)date)[index_date+5] = missing_date.floatval; break; /* identical to option=0, except returns ints */ case -5: ((int*)date)[index_date] = missing_date.intval; ((int*)date)[index_date+1] = missing_date.intval; ((int*)date)[index_date+2] = missing_date.intval; ((int*)date)[index_date+3] = missing_date.intval; ((int*)date)[index_date+4] = missing_date.intval; ((int*)date)[index_date+5] = missing_date.intval; break; case 1: case 2: case 3: case 4: ((double*)date)[index_date] = missing_date.doubleval; break; case -1: case -2: case -3: ((int*)date)[index_date] = missing_date.intval; break; } } if(*option == 0 || *option == -5) { index_date += 6; } else { index_date++; } } /* * Free the work arrays. */ if(type_x != NCL_double) NclFree(tmp_x); /* * Close up Udunits. */ utclose_ncl(unit_system); /* * Free extra units */ NclFree(cspec_orig); ut_free(utunit); /* * Set up variable to return. */ if(has_missing_x) { return_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, date, &missing_date, ndims_date, dsizes_date, TEMPORARY, NULL, type_date_t ); } else { return_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, date, NULL, ndims_date, dsizes_date, TEMPORARY, NULL, type_date_t ); } /* * Set up attributes to return. */ att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL); dsizes[0] = 1; /* * Return "calendar" attribute. * * We can't just return "scal" here, because it's an NCL input * parameter and this seems to screw things up if we try to * return it as an attribute. */ calendar = (NclQuark*)NclMalloc(sizeof(NclQuark)); if(ccal != NULL) { *calendar = NrmStringToQuark(ccal); } else { *calendar = NrmStringToQuark("standard"); } att_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, (void*)calendar, NULL, 1, dsizes, TEMPORARY, NULL, (NclObjClass)nclTypestringClass ); _NclAddAtt( att_id, "calendar", att_md, NULL ); tmp_var = _NclVarCreate( NULL, NULL, Ncl_Var, 0, NULL, return_md, NULL, att_id, NULL, RETURNVAR, NULL, TEMPORARY ); NclFree(dsizes_date); /* * Return output grid and attributes to NCL. */ return_data.kind = NclStk_VAR; return_data.u.data_var = tmp_var; _NclPlaceReturn(return_data); return(NhlNOERROR); }