Exec_stat MCSort::sort_container(MCExecPoint &p_exec_point, Chunk_term p_type, Sort_type p_direction, Sort_type p_form, MCExpression *p_by) { MCSortnode *t_items; uint4 t_item_count; t_item_count = 0; // If sorting items of the container, then we use the current itemDelimiter to split each item, // all other forms of search default to the lineDelimiter for now. Note that this is a slight // change of behavior as previously sorting containers by line ignored the lineDelimiter and // always delimited by ascii 10. char t_delimiter; if (p_type == CT_ITEM) t_delimiter = p_exec_point . getitemdel(); else t_delimiter = p_exec_point . getlinedel(); if (t_delimiter == '\0') return ES_NORMAL; // Calculate the number of items we need to sort, store this in t_item_count. uint4 t_item_size; t_item_size = p_exec_point . getsvalue() . getlength(); char *t_item_text; t_item_text = p_exec_point . getsvalue() . clone(); char *t_string_pointer; t_string_pointer = t_item_text; char *t_end_pointer; bool t_trailing_delim = false; while ((t_end_pointer = strchr(t_string_pointer, t_delimiter)) != NULL) { // knock out last delim for lines with a trailing return char if (p_type != CT_ITEM && t_end_pointer[1] == '\0') { t_end_pointer[0] = '\0'; t_trailing_delim = true; } else t_item_count++; t_string_pointer = t_end_pointer + 1; } // OK-2008-12-11: [[Bug 7503]] - If there are 0 items in the string, don't carry out the search, // this keeps the behavior consistent with previous versions of Revolution. if (t_item_count < 1) { delete t_item_text; return ES_NORMAL; } // Now we know the item count, we can allocate an array of MCSortnodes to store them. t_items = new MCSortnode[t_item_count + 1]; t_item_count = 0; t_string_pointer = t_item_text; // Next, populate the MCSortnodes with all the items to be sorted MCString t_string; do { if ((t_end_pointer = strchr(t_string_pointer, t_delimiter)) != NULL) { *t_end_pointer++ = '\0'; t_string . set(t_string_pointer, t_end_pointer - t_string_pointer - 1); } else t_string . set(t_string_pointer, strlen(t_string_pointer)); MCExecPoint t_exec_point2(p_exec_point); additem(t_exec_point2, t_items, t_item_count, p_form, t_string, p_by); t_items[t_item_count - 1] . data = (void *)t_string_pointer; t_string_pointer = t_end_pointer; } while (t_end_pointer != NULL); // Sort the array MCU_sort(t_items, t_item_count, p_direction, p_form); // Build the output string char *t_output; t_output = new char[t_item_size + 1]; *t_output = '\0'; uint4 t_length; t_length = 0; for (unsigned int i = 0; i < t_item_count; i++) { uint4 t_item_length; t_item_length = strlen((const char *)t_items[i] . data); strncpy(&t_output[t_length], (const char *)t_items[i] . data, t_item_length); t_length = t_length + t_item_length; if ((p_form == ST_INTERNATIONAL || p_form == ST_TEXT) && (!p_exec_point . getcasesensitive() || p_by != NULL)) delete t_items[i] . svalue; if (t_trailing_delim || i < t_item_count - 1) t_output[t_length++] = t_delimiter; } t_output[t_length] = '\0'; p_exec_point . grabbuffer(t_output, t_length); delete t_item_text; delete t_items; return ES_NORMAL; }
Exec_stat MCFunction::evalparams(Functions func, MCParameter *params, MCExecPoint &ep) { uint4 nparams = 0; real8 n, tn, oldn; n = oldn = 0.0; MCSortnode *mditems = NULL; // JS-2013-06-19: [[ StatsFunctions ]] Support for new stats functions based on arithmeticMean if (func == F_AVG_DEV || func == F_POP_STD_DEV || func == F_POP_VARIANCE || func == F_SMP_STD_DEV || func == F_SMP_VARIANCE) { //use recursion to get average first if (evalparams(F_ARI_MEAN, params, ep) != ES_NORMAL) return ES_ERROR; oldn = ep.getnvalue(); } // JS-2013-06-19: [[ StatsFunctions ]] Support for geometricMean if (func == F_GEO_MEAN) { //use recursion to count items first if (evalparams(F_UNDEFINED, params, ep) != ES_NORMAL) return ES_ERROR; oldn = ep.getnvalue(); } if (func == F_MEDIAN) { //use recursion to count items first if (evalparams(F_UNDEFINED, params, ep) != ES_NORMAL) return ES_ERROR; mditems = new MCSortnode[(uint4)ep.getnvalue()]; } if (params != NULL && params->getnext() == NULL) { if (params->eval(ep) != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } if (ep.getformat() == VF_ARRAY) { if (ep.getarray() -> is_array() && ep.getarray()->get_array()->dofunc(ep, func, nparams, n, oldn, mditems) != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } } else { MCString s(ep.getsvalue()); uint4 length = s.getlength(); const char *sptr = s.getstring(); MCU_skip_spaces(sptr, length); while (length != 0) { s.setstring(sptr); if (!MCU_strchr(sptr, length, ',')) { s.setlength(length); length = 0; } else { s.setlength(sptr - s.getstring()); MCU_skip_char(sptr, length); MCU_skip_spaces(sptr, length); } if (s.getlength() == 0) tn = 0.0; else if (!MCU_stor8(s, tn)) { MCeerror->add (EE_FUNCTION_NAN, 0, 0, s); return ES_ERROR; } MCU_dofunc(func, nparams, n, tn, oldn, mditems); } } } else { MCParameter *tparam = params; while (tparam != NULL) { if (tparam->eval(ep) != ES_NORMAL || ep.ton() != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } MCU_dofunc(func, nparams, n, ep.getnvalue(), oldn, mditems); tparam = tparam->getnext(); } } if (nparams != 0) switch (func) { // JS-2013-06-19: [[ StatsFunctions ]] Support for arithmeticMean (was average) case F_ARI_MEAN: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for averageDeviation case F_AVG_DEV: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for harmonicMean case F_HAR_MEAN: n = nparams/n; break; case F_MEDIAN: { uint4 toffset; MCU_sort(mditems, nparams, ST_ASCENDING, ST_NUMERIC); toffset = (nparams + 1)/2 - 1; if ((nparams % 2) != 0) //odd n = mditems[toffset].nvalue; else //even average 2 closest values n = (mditems[toffset].nvalue + mditems[toffset+1].nvalue)/2; break; } // JS-2013-06-19: [[ StatsFunctions ]] Support for populationStandardDeviation case F_POP_STD_DEV: n = sqrt(n/nparams); break; // JS-2013-06-19: [[ StatsFunctions ]] Support for populationVariance case F_POP_VARIANCE: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for sampleStandardDeviation (was stdDev) case F_SMP_STD_DEV: n = sqrt(n/(nparams - 1)); break; // JS-2013-06-19: [[ StatsFunctions ]] Support for sampleVariance case F_SMP_VARIANCE: n /= nparams - 1; break; case F_UNDEFINED: n = nparams; break; default: break; } ep.setnvalue(n); delete mditems; return ES_NORMAL; }