// MW-2008-03-18: [[ Bug 3300 ]] Make sure that if a file has a full path we dont' prepend // the selected folder. // MW-2008-03-18: [[ Bug 6116 ]] Make sure that we don't add an extra slash if there's already // one at the end of the folder path. static void build_path(MCStringRef p_folder, MCStringRef p_file, MCStringRef x_path) { MCAutoStringRef t_path, t_engine_path; MCStringCreateMutable(0, &t_path); MCS_pathfromnative(p_file, &t_engine_path); // Check for absolute paths bool t_use_folder; if (MCStringIsEmpty(p_folder) || (MCStringGetLength(*t_engine_path) > 1 && MCStringGetCharAtIndex(*t_engine_path, 1) == ':') || (MCStringGetLength(*t_engine_path) > 2 && MCStringGetCharAtIndex(*t_engine_path, 0) == '/' && MCStringGetCharAtIndex(*t_engine_path, 1) == '/')) { t_use_folder = false; } else { t_use_folder = true; } if (t_use_folder) { // Add the folder and a separator, if required MCStringAppend(*t_path, p_folder); if (MCStringGetCharAtIndex(p_folder, MCStringGetLength(p_folder) - 1) != '/') MCStringAppendChar(*t_path, '/'); } MCStringAppend(*t_path, *t_engine_path); if (*t_path != nil) MCStringAppend(x_path, *t_path); }
Boolean MCEPS::import(MCStringRef fname, IO_handle stream) { size = (uint4)MCS_fsize(stream); delete postscript; postscript = new char[size + 1]; if (IO_read(postscript, size, stream) != IO_NORMAL) return False; postscript[size] = '\0'; uindex_t t_sep; MCStringRef t_fname; if (MCStringLastIndexOfChar(fname, PATH_SEPARATOR, UINDEX_MAX, kMCCompareExact, t_sep)) /* UNCHECKED */ MCStringCopySubstring(fname, MCRangeMake(t_sep + 1, MCStringGetLength(fname) - (t_sep + 1)), t_fname); else t_fname = MCValueRetain(fname); MCNewAutoNameRef t_name; if (!MCNameCreateAndRelease(t_fname, &t_name)) return False; setname(*t_name); setextents(); rect.width = (uint2)(ex * xscale / xf); rect.height = (uint2)(ey * yscale / yf); if (flags & F_SHOW_BORDER) { rect.width += borderwidth << 1; rect.height += borderwidth << 1; } return True; }
int MCR_exec(regexp *prog, MCStringRef string, MCRange p_range) { // AL-2014-06-25: [[ Bug 12676 ]] Ensure string is not unnativized by MCR_exec int status; int flags = 0; if (MCStringIsNative(string)) { uindex_t t_length; unichar_t *t_string_chars; t_string_chars = nil; MCMemoryAllocate(MCStringGetLength(string) * sizeof(unichar_t), t_string_chars); t_length = MCStringGetChars(string, p_range, t_string_chars); status = regexec(&prog->rexp, t_string_chars, t_length, NSUBEXP, prog->matchinfo, flags); MCMemoryDeallocate(t_string_chars); } else status = regexec(&prog->rexp, MCStringGetCharPtr(string) + p_range . offset, p_range . length, NSUBEXP, prog->matchinfo, flags); if (status != REG_OKAY) { if (status == REG_NOMATCH) { return (0); } //MCValueRelease(regexperror); regerror(status, NULL, regexperror); return(0); } return (1); }
void MCDebuggingSetDebugContext(MCExecContext& ctxt, MCStringRef p_value) { uindex_t t_length = MCStringGetLength(p_value); bool t_in_quotes; t_in_quotes = false; uindex_t t_offset; /*for (t_offset = 0; t_offset < t_length; t_offset++) { if (!t_in_quotes && MCStringGetNativeCharAtIndex(p_value, t_offset) == ',') break; if (MCStringGetNativeCharAtIndex(p_value, t_offset) == '"') t_in_quotes = !t_in_quotes; } if (t_offset < t_length)*/ if (MCStringLastIndexOfChar(p_value, ',', t_length, kMCStringOptionCompareExact, t_offset)) { MCAutoStringRef t_head; MCAutoStringRef t_tail; int4 t_line; MCObjectPtr t_object; if (MCStringDivideAtIndex(p_value, t_offset, &t_head, &t_tail) && MCInterfaceTryToResolveObject(ctxt, *t_head, t_object) && MCU_strtol(*t_tail, t_line)) { for (uint2 i = 0; i < MCnexecutioncontexts; i++) { if (MCexecutioncontexts[i] -> GetObject() == t_object . object && MCexecutioncontexts[i] -> GetLine() == t_line) { MCdebugcontext = i; break; } } return; } } else { int4 i; if (MCU_strtol(p_value, i) && i <= MCnexecutioncontexts) MCdebugcontext = i - 1; else MCdebugcontext = MAXUINT2; return; } ctxt . Throw(); }
void MCButton::SetAcceleratorKey(MCExecContext& ctxt, MCStringRef p_name) { if (p_name != nil) { accelkey = MCStringGetCharAtIndex(p_name, 0); if (MCStringGetLength(p_name) > 1) { uint4 t_accelkey = MCLookupAcceleratorKeysym(p_name); if (t_accelkey != 0) accelkey = t_accelkey; } } else accelkey = 0; MCstacks->changeaccelerator(this, accelkey, accelmods); }
bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_count, bool& r_all_integers) { r_indexes = nil; r_count = 0; MCStringRef t_string = MCNameGetString(p_key); uindex_t t_string_len = MCStringGetLength(t_string); if (t_string_len == 0) return true; r_all_integers = true; uindex_t t_start, t_finish; t_start = 0; t_finish = 0; for(;;) { if (!MCStringFirstIndexOfChar(t_string, ',', t_start, kMCCompareExact, t_finish)) t_finish = t_string_len; if (!MCMemoryResizeArray(r_count + 1, r_indexes, r_count)) return false; MCAutoStringRef t_substring; MCAutoNumberRef t_number; MCStringCopySubstring(t_string, MCRangeMake(t_start, t_finish - t_start), &t_substring); if (!MCNumberParse(*t_substring, &t_number)) { r_indexes[r_count - 1] = 0; r_all_integers = false; break; } else r_indexes[r_count - 1] = MCNumberFetchAsInteger(*t_number); if (t_finish >= t_string_len) break; t_start = t_finish + 1; } return true; }
void MCDebuggingSetTraceStack(MCExecContext& ctxt, MCStringRef p_value) { if (MCStringGetLength(p_value) == 0) { MCtracestackptr = nil; return; } MCStack *sptr; sptr = MCdefaultstackptr->findstackname_string(p_value); if (sptr == nil) { ctxt . LegacyThrow(EE_PROPERTY_NODEFAULTSTACK); return; } MCtracestackptr = sptr; }
bool MCPurchaseInit(MCPurchase *p_purchase, MCStringRef p_product_id, void *p_context) { bool t_success = true; if (p_context != nil) p_purchase->platform_data = p_context; else { MCAndroidPurchase *t_android_data = nil; t_success = MCStringGetLength(p_product_id) != 0; if (t_success) t_success = MCMemoryNew(t_android_data); if (t_success) t_android_data->product_id = MCValueRetain(p_product_id); if (t_success) p_purchase->platform_data = t_android_data; else MCMemoryDelete(t_android_data); } return t_success; }
IO_stat MCImage::import(MCStringRef newname, IO_handle stream, IO_handle mstream) { bool t_success = true; MCImageCompressedBitmap *t_compressed = nil; MCImageBitmap *t_bitmap = nil; MCStringRef t_name = nil; MCPoint t_hotspot = {1, 1}; t_success = MCImageImport(stream, mstream, t_hotspot, t_name, t_compressed, t_bitmap); if (t_success) { if (t_compressed == nil) t_success = setbitmap(t_bitmap, 1.0); else t_success = setcompressedbitmap(t_compressed); } MCImageFreeCompressedBitmap(t_compressed); MCImageFreeBitmap(t_bitmap); uindex_t t_width, t_height; if (t_success) t_success = getsourcegeometry(t_width, t_height); if (t_success) { xhot = t_hotspot.x; yhot = t_hotspot.y; bool t_resize = true; t_resize = !(flags & F_LOCK_LOCATION); if (t_resize) { rect.width = t_width; rect.height = t_height; } if (m_rep->GetFrameCount() > 1) { if ((flags & F_REPEAT_COUNT) == 0) repeatcount = -1; irepeatcount = repeatcount; state |= CS_DO_START; } if (isunnamed() && t_name != nil) { MCNewAutoNameRef t_name_nameref; /* UNCHECKED */ MCNameCreate(t_name, &t_name_nameref); setname(*t_name_nameref); } if (isunnamed() && newname != nil) { MCNewAutoNameRef t_name_nameref; uindex_t t_offset; if (MCStringLastIndexOfChar(newname, PATH_SEPARATOR, UINDEX_MAX, kMCCompareExact, t_offset)) { /* UNCHECKED */ MCStringCopySubstring(newname, MCRangeMakeMinMax(t_offset + 1, MCStringGetLength(newname)), t_name); /* UNCHECKED */ MCNameCreate(t_name, &t_name_nameref); } else /* UNCHECKED */ MCNameCreate(newname, &t_name_nameref); setname(*t_name_nameref); } } MCValueRelease(t_name); return t_success ? IO_NORMAL : IO_ERROR; }
void MCArraysExecSplitByColumn(MCExecContext& ctxt, MCStringRef p_string, MCArrayRef& r_array) { MCStringRef t_row_delim, t_column_delim; t_row_delim = ctxt . GetRowDelimiter(); t_column_delim = ctxt . GetColumnDelimiter(); // Output array MCAutoArrayRef t_array; if (!MCArrayCreateMutable(&t_array)) { ctxt . Throw(); return; } // Temporary array for storing columns MCAutoArray<MCStringRef> t_temp_array; // Iterate over the rows of the input string uindex_t t_offset, t_length; t_offset = 0; t_length = MCStringGetLength(p_string); bool t_success; t_success = true; uindex_t t_row_index; t_row_index = 0; while (t_success && t_offset < t_length) { // Find the end of this row MCRange t_row_found; if (!MCStringFind(p_string, MCRangeMake(t_offset, UINDEX_MAX), t_row_delim, ctxt . GetStringComparisonType(), &t_row_found)) { t_row_found . offset = t_length; t_row_found . length = 0; } // Iterate over the cells of this row uindex_t t_cell_offset, t_column_index; t_cell_offset = t_offset; t_column_index = 0; while (t_success && t_cell_offset <= t_row_found . offset) { // Find the end of this cell MCRange t_cell_found; if (!MCStringFind(p_string, MCRangeMake(t_cell_offset, UINDEX_MAX), t_column_delim, ctxt . GetStringComparisonType(), &t_cell_found) || t_cell_found . offset > t_row_found . offset) { t_cell_found . offset = t_row_found . offset; // AL-2014-08-04: [[ Bug 13090 ]] Make sure cell offset is incremented eventually when the delimiter is not found t_cell_found . length = 1; } // Check that the output array has a slot for this column if (t_temp_array.Size() <= t_column_index) t_temp_array.Extend(t_column_index + 1); // Check that a string has been created to store this column MCRange t_range; t_range = MCRangeMake(t_cell_offset, t_cell_found . offset - t_cell_offset); if (t_temp_array[t_column_index] == nil) { t_success = MCStringCreateMutable(0, t_temp_array[t_column_index]); // AL-2014-08-04: [[ Bug 13090 ]] If we are creating a new column, make sure we pad with empty cells 'above' this one uindex_t t_rows = t_row_index; while (t_success && t_rows--) t_success = MCStringAppend(t_temp_array[t_column_index], t_row_delim); if (t_success) t_success = MCStringAppendFormat(t_temp_array[t_column_index], "%*@", &t_range, p_string); } else { // AL-2014-06-12: [[ Bug 12610 ]] Range parameter to MCStringFormat must be a pointer to an MCRange t_success = MCStringAppendFormat(t_temp_array[t_column_index], "%@%*@", t_row_delim, &t_range, p_string); } // Next cell t_column_index++; t_cell_offset = t_cell_found . offset + t_cell_found . length; } // AL-2014-08-04: [[ Bug 13090 ]] Pad the rest of this row with empty cells index_t t_pad_number; t_pad_number = t_temp_array . Size() - t_column_index; if (t_success && t_pad_number > 0) { while (t_success && t_pad_number--) t_success = MCStringAppend(t_temp_array[t_column_index++], t_row_delim); } // Next row t_row_index++; t_offset = t_row_found . offset + t_row_found . length; } // Convert the temporary array into a "proper" array for (uindex_t i = 0; i < t_temp_array.Size() && t_success; i++) { t_success = MCArrayStoreValueAtIndex(*t_array, i + 1, t_temp_array[i]); MCValueRelease(t_temp_array[i]); } if (t_success) t_success = MCArrayCopy(*t_array, r_array); if (!t_success) ctxt . Throw(); }
// SN-2014-09-01: [[ Bug 13297 ]] Combining by column deserves its own function as it is too // different from combining by row void MCArraysExecCombineByColumn(MCExecContext& ctxt, MCArrayRef p_array, MCStringRef &r_string) { MCStringRef t_row_delimiter, t_col_delimiter; t_row_delimiter = ctxt . GetRowDelimiter(); t_col_delimiter = ctxt . GetColumnDelimiter(); MCAutoListRef t_list; MCListCreateMutable(t_row_delimiter, &t_list); uindex_t t_count = MCArrayGetCount(p_array); combine_int_indexed_array_t t_lisctxt; bool t_success; t_lisctxt . elements = nil; t_lisctxt . index = 0; t_lisctxt . converter = &ctxt; t_success = MCMemoryNewArray(t_count, t_lisctxt . elements); if (t_success) { if (MCArrayApply(p_array, list_int_indexed_array_elements, &t_lisctxt)) { bool t_valid_keys; qsort(t_lisctxt . elements, t_count, sizeof(array_element_t), compare_int_indexed_elements); // Combine by row/column is only valid if all the indices are consecutive numbers // Otherwise, an empty string is returned - no error index_t t_last_index; t_valid_keys = true; t_last_index = 0; for (int i = 0; i < t_count && t_valid_keys; ++i) { if (!t_last_index) t_last_index = t_lisctxt . elements[i] . key; else t_valid_keys = ++t_last_index == t_lisctxt . elements[i] . key; } if (t_valid_keys) { // SN-2014-09-01: [[ Bug 13297 ]] // We need to store the converted strings in a array, to be able to iterate through the elements by one row-delimitated // at a time MCStringRef* t_strings; uindex_t *t_next_row_indices; t_strings = NULL; t_next_row_indices = NULL; /* UNCHECKED */ MCMemoryNewArray(t_count, t_strings); // MCMemoryNewArray initialises all t_next_row_indices elements to 0. /* UNCHECKED */ MCMemoryNewArray(t_count, t_next_row_indices); for (int i = 0; i < t_count && t_success; ++i) { if (t_lisctxt . elements[i] . key == 0) // The index 0 is ignored continue; t_success = ctxt . ConvertToString(t_lisctxt . elements[i] . value, t_strings[i]); } // SN-2014-09-01: [[ Bug 13297 ]] Added a missed part in column-combining: // only combining row-by-row the array elements. if (t_success) { uindex_t t_elements_over; t_elements_over = 0; // We iterate as long as one element still has uncombined rows while (t_success && t_elements_over != t_count) { MCAutoListRef t_row; t_success = MCListCreateMutable(t_col_delimiter, &t_row); t_elements_over = 0; // Iterate through all the elements of the array for (int i = 0; i < t_count && t_success; ++i) { // Only consider this element if it has any uncombined rows remaining if (t_next_row_indices[i] < MCStringGetLength(t_strings[i])) { MCRange t_cell_range; if (MCStringFind(t_strings[i], MCRangeMake(t_next_row_indices[i], UINDEX_MAX), t_row_delimiter, ctxt.GetStringComparisonType(), &t_cell_range)) { // We found a row delimiter, so we stop the copy range before it and update the next index from which to look t_success = MCListAppendSubstring(*t_row, t_strings[i], MCRangeMake(t_next_row_indices[i], t_cell_range . offset - t_next_row_indices[i])); t_next_row_indices[i] = t_cell_range . offset + t_cell_range . length; } else { // No row delimiter: we copy the remaining part of the string and mark the element // as wholly combined by setting the next index to the length of the element t_success = MCListAppendSubstring(*t_row, t_strings[i], MCRangeMake(t_next_row_indices[i], UINDEX_MAX)); t_next_row_indices[i] = MCStringGetLength(t_strings[i]); } } else { // Everything has been combined in this element t_elements_over++; MCListAppend(*t_row, kMCEmptyString); } } // One more row has been combined - doing it anyway mimics the previous behaviour of having an empty row // added in the end when combining by columns if (t_elements_over != t_count) MCListAppend(*t_list, *t_row); } } MCMemoryDeleteArray(t_next_row_indices); MCMemoryDeleteArray(t_strings); } } MCMemoryDeleteArray(t_lisctxt . elements); } if (t_success && MCListCopyAsString(*t_list, r_string)) return; ctxt . Throw(); }
Exec_stat MCF_parsetextatts(Properties which, MCStringRef data, uint4 &flags, MCStringRef &fname, uint2 &height, uint2 &size, uint2 &style) { int2 i1; switch (which) { case P_TEXT_ALIGN: flags &= ~F_ALIGNMENT; if (MCStringIsEqualToCString(data, MCleftstring, kMCCompareCaseless) || MCStringIsEmpty(data)) flags |= F_ALIGN_LEFT; else if (MCStringIsEqualToCString(data, MCcenterstring, kMCCompareCaseless)) flags |= F_ALIGN_CENTER; else if (MCStringIsEqualToCString(data, MCrightstring, kMCCompareCaseless)) flags |= F_ALIGN_RIGHT; else if (MCStringIsEqualToCString(data, MCjustifystring, kMCCompareCaseless)) flags |= F_ALIGN_JUSTIFY; else { MCeerror->add(EE_OBJECT_BADALIGN, 0, 0, data); return ES_ERROR; } break; case P_TEXT_FONT: {// MW-2012-02-17: [[ IntrinsicUnicode ]] Strip any lang tag from the // fontname. uindex_t t_offset; if (MCStringFirstIndexOfChar(data, ',', 0, kMCCompareExact, t_offset)) /* UNCHECKED */ MCStringCopySubstring(data, MCRangeMake(t_offset + 1, MCStringGetLength(data) - (t_offset + 1)), fname); else fname = MCValueRetain(data); } break; case P_TEXT_HEIGHT: if (!MCU_stoi2(data, i1)) { MCeerror->add (EE_OBJECT_TEXTHEIGHTNAN, 0, 0, data); return ES_ERROR; } height = i1; break; case P_TEXT_SIZE: if (MCStringIsEmpty(data)) i1 = 0; else if (!MCU_stoi2(data, i1)) { MCeerror->add (EE_OBJECT_TEXTSIZENAN, 0, 0, data); return ES_ERROR; } size = i1; break; case P_TEXT_STYLE: { // MW-2012-02-17: [[ SplitTextAttrs ]] If the string is empty, then // return 0 for the style - indicating to unset the property. if (MCStringIsEmpty(data)) style = 0; else { style = FA_DEFAULT_STYLE; uindex_t t_start_pos, t_end_pos; t_end_pos = 0; while (t_end_pos < MCStringGetLength(data)) { t_start_pos = t_end_pos; // skip spaces at the beginning or after a comma (if any) MCU_skip_spaces(data, t_start_pos); uindex_t t_comma; if (!MCStringFirstIndexOfChar(data, ',', t_start_pos, kMCCompareExact, t_comma)) t_end_pos = MCStringGetLength(data); else t_end_pos = t_comma; MCAutoStringRef tdata; /* UNCHECKED */ MCStringCopySubstring(data, MCRangeMake(t_start_pos, t_end_pos - t_start_pos), &tdata); t_end_pos++; if (MCF_setweightstring(style, *tdata)) continue; if (MCF_setexpandstring(style, *tdata)) continue; if (MCF_setslantlongstring(style, *tdata)) continue; if (MCStringIsEqualToCString(*tdata, MCplainstring, kMCCompareCaseless)) { style = FA_DEFAULT_STYLE; continue; } if (MCStringIsEqualToCString(*tdata, MCmixedstring, kMCCompareCaseless)) { style = FA_DEFAULT_STYLE; continue; } if (MCStringIsEqualToCString(*tdata, MCboxstring, kMCCompareCaseless)) { style &= ~FA_3D_BOX; style |= FA_BOX; continue; } if (MCStringIsEqualToCString(*tdata, MCthreedboxstring, kMCCompareCaseless)) { style &= ~FA_BOX; style |= FA_3D_BOX; continue; } if (MCStringIsEqualToCString(*tdata, MCunderlinestring, kMCCompareCaseless)) { style |= FA_UNDERLINE; continue; } if (MCStringIsEqualToCString(*tdata, MCstrikeoutstring, kMCCompareCaseless)) { style |= FA_STRIKEOUT; continue; } if (MCStringIsEqualToCString(*tdata, MCgroupstring, kMCCompareCaseless) || MCStringIsEqualToCString(*tdata, MClinkstring, kMCCompareCaseless)) { style |= FA_LINK; continue; } MCeerror->add(EE_OBJECT_BADSTYLE, 0, 0, data); return ES_ERROR; } } } break; default: break; } return ES_NORMAL; }
void MCFontDrawText(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCFontRef font, bool p_rtl, bool p_can_break) { MCRange t_range = MCRangeMake(0, MCStringGetLength(p_text)); return MCFontDrawTextSubstring(p_gcontext, x, y, p_text, t_range, font, p_rtl, p_can_break); }
int32_t MCFontMeasureText(MCFontRef p_font, MCStringRef p_text, const MCGAffineTransform &p_transform) { MCRange t_range = MCRangeMake(0, MCStringGetLength(p_text)); return MCFontMeasureTextSubstring(p_font, p_text, t_range, p_transform); }
void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback p_callback, void *p_callback_data, bool p_rtl) { // MW-2013-12-19: [[ Bug 11559 ]] If the font has a nil font, do nothing. if (p_font -> fontstruct == nil) return; // If the text is small enough, don't bother trying to break it /*if (p_length <= (kMCFontBreakTextCharLimit * (p_is_unicode ? 2 : 1))) { p_callback(p_font, p_text, p_length, p_is_unicode, p_callback_data); return; }*/ //p_callback(p_font, p_text, p_length, p_is_unicode, p_callback_data); //return; // Scan forward in the string for possible break locations. Breaks are // assigned a quality value as some locations are better for breaking than // others. The qualities are: // // 0. no break found // 1. grapheme break found // 2. URL break found ('/' char) // 3. word break found // // This isn't a particularly good algorithm but should suffice until full // Unicode support is added and a proper breaking algorithm implemented. uint32_t t_stride; t_stride = kMCFontBreakTextCharLimit; uindex_t t_end = p_range.offset + p_range.length; uindex_t t_length = p_range.length; uindex_t t_offset = (p_rtl) ? 0 : p_range.offset; while (t_length > 0) { int t_break_quality; uindex_t t_break_point, t_index; t_break_quality = 0; t_break_point = 0; t_index = 0; // Find the best break within the next stride characters. If there are // no breaking points, extend beyond the stride until one is found. while ((t_index < t_stride || t_break_quality == 0) && t_index < t_length) { codepoint_t t_char; uindex_t t_advance; if (p_rtl) t_char = MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset); else t_char = MCStringGetCharAtIndex(p_text, t_offset + t_index); if (MCUnicodeCodepointIsHighSurrogate(t_char)) { // Surrogate pair if (p_rtl) t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset - 1)); else t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_offset + t_index + 1)); t_advance = 2; } else { t_advance = 1; } // Prohibit breaks at the beginning of the string if (t_index == 0) { t_index += t_advance; continue; } if (t_char == ' ') { t_break_point = t_index; t_break_quality = 3; } else if (t_break_quality < 3 && t_char == '/') { t_break_point = t_index; t_break_quality = 2; } else if (t_break_quality < 2 && MCUnicodeCodepointIsBase(t_char)) { t_break_point = t_index; t_break_quality = 1; } else if (t_break_quality < 2 && t_char > 0xFFFF) { // Character outside BMP, assume can break here t_break_point = t_index; t_break_quality = 1; } // If the break point is a word boundary, don't look for a later // breaking point. Words are cached as-is where possible. if (t_break_quality == 3) break; // Advance to the next character t_index += t_advance; } // If no word break was found and the whole of the remaining text was // searched and the remaining text is smaller than the break size then // don't attempt a break just for the sake of it. if (t_break_quality < 3 && t_length < kMCFontBreakTextCharLimit) t_break_point = t_length; // If no break point was found, just process the whole line if (t_break_quality == 0) t_break_point = t_length; // Process this chunk of text MCRange t_range; if (p_rtl) t_range = MCRangeMake(t_end - t_offset - t_break_point, t_break_point); else t_range = MCRangeMake(t_offset, t_break_point); #if !defined(_WIN32) && !defined(_ANDROID_MOBILE) // This is a really ugly hack to get LTR/RTL overrides working correctly - // ATSUI and Pango think they know better than us and won't let us suppress // the BiDi algorithm they uses for text layout. So instead, we need to add // an LRO or RLO character in front of every single bit of text :-( MCAutoStringRef t_temp; unichar_t t_override; if (p_rtl) t_override = 0x202E; else t_override = 0x202D; /* UNCHECKED */ MCStringCreateMutable(0, &t_temp); /* UNCHECKED */ MCStringAppendChar(*t_temp, t_override); /* UNCHECKED */ MCStringAppendSubstring(*t_temp, p_text, t_range); /* UNCHECKED */ MCStringAppendChar(*t_temp, 0x202C); p_callback(p_font, *t_temp, MCRangeMake(0, MCStringGetLength(*t_temp)), p_callback_data); #else // Another ugly hack - this time, to avoid incoming strings being coerced // into Unicode strings needlessly (because the drawing code uses unichars). // Do a mutable copy (to ensure an actual copy) before drawing. MCAutoStringRef t_temp; /* UNCHECKED */ MCStringMutableCopySubstring(p_text, t_range, &t_temp); p_callback(p_font, *t_temp, MCRangeMake(0, t_range.length), p_callback_data); #endif // Explicitly show breaking points //p_callback(p_font, MCSTR("|"), MCRangeMake(0, 1), p_callback_data); // Move on to the next chunk t_offset += t_break_point; // SN-2014-07-23: [[ Bug 12910 ]] Script editor crashes // Make sure we get 0 as a minimum, not a negative value since t_length is a uindex_t. if (t_length < t_break_point) t_length = 0; else t_length -= t_break_point; } }
static int MCA_do_file_dialog(MCStringRef p_title, MCStringRef p_prompt, MCStringRef p_filter, MCStringRef p_initial, unsigned int p_options, MCStringRef &r_value, MCStringRef &r_result) { int t_result = 0; MCAutoStringRef t_initial_file; MCAutoStringRef t_initial_folder; MCAutoStringRef t_initial_native_folder; if (p_initial != nil && !MCStringIsEmpty(p_initial)) { MCAutoStringRef t_fixed_path; /* UNCHECKED */ MCU_fix_path(p_initial, &t_fixed_path); if (MCS_exists(*t_fixed_path, False)) t_initial_folder = *t_fixed_path; else if ((p_options & MCA_OPTION_SAVE_DIALOG) != 0) { uindex_t t_last_slash; if (!MCStringLastIndexOfChar(*t_fixed_path, '/', UINDEX_MAX, kMCStringOptionCompareExact, t_last_slash)) { if (MCStringGetLength(*t_fixed_path) != 0) t_initial_file = *t_fixed_path; } else { if (t_last_slash < MCStringGetLength(*t_fixed_path) - 1) /* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(t_last_slash + 1, MCStringGetLength(*t_fixed_path) - (t_last_slash + 1)), &t_initial_file); MCAutoStringRef t_folder_split; /* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(0, t_last_slash - 1), &t_folder_split); if (MCS_exists(*t_folder_split, False)) t_initial_folder = *t_folder_split; } } else { uindex_t t_last_slash; if (MCStringLastIndexOfChar(*t_fixed_path, '/', UINDEX_MAX, kMCStringOptionCompareExact, t_last_slash)) { MCAutoStringRef t_folder_split; /* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(0, t_last_slash - 1), &t_folder_split); if (MCS_exists(*t_folder_split, False)) t_initial_folder = *t_folder_split; } } MCAutoStringRef t_resolved_folder; /* UNCHECKED */ MCS_resolvepath(*t_initial_folder != nil ? *t_initial_folder : kMCEmptyString, &t_resolved_folder); /* UNCHECKED */ MCS_pathtonative(*t_resolved_folder, &t_initial_native_folder); } if (!MCModeMakeLocalWindows()) { MCAutoStringRefArray t_filters; if (p_filter != NULL) { /* UNCHECKED */ MCStringsSplit(p_filter, '\0', t_filters.PtrRef(), t_filters.CountRef()); } MCRemoteFileDialog(p_title, p_prompt, *t_filters, t_filters.Count(), *t_initial_native_folder, *t_initial_file, (p_options & MCA_OPTION_SAVE_DIALOG) != 0, (p_options & MCA_OPTION_PLURAL) != 0, r_value); return 0; } Window t_window; t_window = MCModeGetParentWindow(); MCAutoStringRef t_value; bool t_succeeded; int t_filter_index; if (MCmajorosversion >= 0x0600) { static SHCreateItemFromParsingNamePtr s_shcreateitemfromparsingname = NULL; if (s_shcreateitemfromparsingname == NULL) { static HMODULE s_shell32_module = NULL; s_shell32_module = LoadLibraryW(L"shell32.dll"); s_shcreateitemfromparsingname = (SHCreateItemFromParsingNamePtr)GetProcAddress(s_shell32_module, "SHCreateItemFromParsingName"); } IFileSaveDialog *t_file_save_dialog; IFileOpenDialog *t_file_open_dialog; IFileDialog *t_file_dialog; t_file_dialog = NULL; HRESULT t_hresult; if ((p_options & MCA_OPTION_SAVE_DIALOG) == 0) { t_hresult = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, __uuidof(IFileOpenDialog), (LPVOID *)&t_file_open_dialog); t_succeeded = SUCCEEDED(t_hresult); t_file_dialog = t_file_open_dialog; } else { t_hresult = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, __uuidof(IFileSaveDialog), (LPVOID *)&t_file_save_dialog); t_succeeded = SUCCEEDED(t_hresult); t_file_dialog = t_file_save_dialog; } if (t_succeeded) { DWORD t_options; t_options = FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_PATHMUSTEXIST; if (p_options & MCA_OPTION_PLURAL) t_options |= FOS_ALLOWMULTISELECT; if (p_options & MCA_OPTION_SAVE_DIALOG) t_options |= FOS_OVERWRITEPROMPT; if (p_options & MCA_OPTION_FOLDER_DIALOG) t_options |= FOS_PICKFOLDERS; else t_options |= FOS_FILEMUSTEXIST; t_hresult = t_file_dialog -> SetOptions(t_options); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded && *t_initial_native_folder != NULL) { IShellItem *t_initial_folder_shellitem; t_initial_folder_shellitem = NULL; MCAutoStringRefAsWString t_initial_folder_wstr; /* UNCHECKED */ t_initial_folder_wstr.Lock(*t_initial_native_folder); t_hresult = s_shcreateitemfromparsingname(*t_initial_folder_wstr, NULL, __uuidof(IShellItem), (LPVOID *)&t_initial_folder_shellitem); if (SUCCEEDED(t_hresult)) t_file_dialog -> SetFolder(t_initial_folder_shellitem); if (t_initial_folder_shellitem != NULL) t_initial_folder_shellitem -> Release(); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded && *t_initial_file != NULL) { MCAutoStringRefAsWString t_initial_file_wstr; /* UNCHECKED */ t_initial_file_wstr.Lock(*t_initial_file); t_hresult = t_file_dialog -> SetFileName(*t_initial_file_wstr); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded && p_filter != NULL && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0) { uint4 t_filter_length, t_filter_count; measure_filter(p_filter, t_filter_length, t_filter_count); MCAutoStringRefAsWString t_filter_wstr; /* UNCHECKED */ t_filter_wstr.Lock(p_filter); COMDLG_FILTERSPEC *t_filter_spec; filter_to_spec(*t_filter_wstr, t_filter_count, t_filter_spec); t_hresult = t_file_dialog -> SetFileTypes(t_filter_count, t_filter_spec); t_succeeded = SUCCEEDED(t_hresult); delete t_filter_spec; } if (t_succeeded && p_filter != NULL && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0) { t_hresult = t_file_dialog -> SetFileTypeIndex(1); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded) { MCAutoStringRefAsWString t_prompt_wstr; /* UNCHECKED */ t_prompt_wstr.Lock(p_prompt); t_hresult = t_file_dialog -> SetTitle(*t_prompt_wstr); } if (t_succeeded) { t_hresult = t_file_dialog -> Show(t_window != NULL ? (HWND)t_window -> handle . window : NULL); t_succeeded = SUCCEEDED(t_hresult); } if ((p_options & MCA_OPTION_SAVE_DIALOG) == 0) { IShellItemArray *t_file_items; t_file_items = NULL; if (t_succeeded) { t_hresult = t_file_open_dialog -> GetResults(&t_file_items); t_succeeded = SUCCEEDED(t_hresult); } DWORD t_file_item_count; if (t_succeeded) { t_hresult = t_file_items -> GetCount(&t_file_item_count); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded) { for(uint4 t_index = 0; t_index < t_file_item_count && t_succeeded; ++t_index) { IShellItem *t_file_item; t_file_item = NULL; if (t_succeeded) { t_hresult = t_file_items -> GetItemAt(t_index, &t_file_item); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded) { t_hresult = append_shellitem_path_and_release(t_file_item, t_index == 0, &t_value); t_succeeded = SUCCEEDED(t_hresult); } } } if (t_file_items != NULL) t_file_items -> Release(); } else { IShellItem *t_file_item; t_file_item = NULL; if (t_succeeded) { t_hresult = t_file_dialog -> GetResult(&t_file_item); t_succeeded = SUCCEEDED(t_hresult); } if (t_succeeded) { t_hresult = append_shellitem_path_and_release(t_file_item, true, &t_value); t_succeeded = SUCCEEDED(t_hresult); } } t_filter_index = 0; if (t_succeeded && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0) { UINT t_index; t_hresult = t_file_dialog -> GetFileTypeIndex(&t_index); t_succeeded = SUCCEEDED(t_hresult); if (t_succeeded) t_filter_index = (int)t_index; } if (t_file_dialog != NULL) t_file_dialog -> Release(); if (!t_succeeded) t_result = t_hresult; else t_result = 0; } else { OPENFILENAMEW t_open_dialog; memset(&t_open_dialog, 0, sizeof(OPENFILENAMEW)); t_open_dialog . lStructSize = sizeof(OPENFILENAMEW); MCAutoStringRefAsWString t_initial_folder_wstr; MCAutoStringRefAsWString t_prompt_wstr; MCAutoStringRefAsWString t_filter_wstr; /* UNCHECKED */ t_filter_wstr.Lock(p_filter); /* UNCHECKED */ t_initial_folder_wstr.Lock(*t_initial_native_folder); /* UNCHECKED */ t_prompt_wstr.Lock(p_prompt); MCAutoArray<unichar_t> t_buffer; /* UNCHECKED */ t_buffer.New(MAX_PATH); if (!MCStringIsEmpty(*t_initial_file)) /* UNCHECKED */ MCStringGetChars(*t_initial_file, MCRangeMake(0, t_buffer.Size()), t_buffer.Ptr()); else t_buffer[0] = '\0'; t_open_dialog . lpstrFilter = *t_filter_wstr; t_open_dialog . nFilterIndex = 1; t_open_dialog . lpstrFile = t_buffer.Ptr(); t_open_dialog . nMaxFile = t_buffer.Size(); t_open_dialog . lpstrInitialDir = *t_initial_folder_wstr; t_open_dialog . lpstrTitle = *t_prompt_wstr; t_open_dialog . Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING; if (p_options & MCA_OPTION_PLURAL) t_open_dialog . Flags |= OFN_ALLOWMULTISELECT; if (p_options & MCA_OPTION_SAVE_DIALOG) t_open_dialog . Flags |= OFN_OVERWRITEPROMPT; t_open_dialog . lpstrFilter = *t_filter_wstr; t_open_dialog . lpfnHook = open_dialog_hook; t_open_dialog . hwndOwner = t_window != NULL ? (HWND)t_window -> handle . window : NULL; if (p_options & MCA_OPTION_SAVE_DIALOG) t_succeeded = GetSaveFileNameW(&t_open_dialog) == TRUE; else { *t_open_dialog . lpstrFile = '\0'; t_succeeded = GetOpenFileNameW(&t_open_dialog) == TRUE; } if (!t_succeeded) t_result = CommDlgExtendedError(); // MW-2005-07-26: Try again without the specified filename if it was invalid if (t_result == FNERR_INVALIDFILENAME) { *t_open_dialog . lpstrFile = '\0'; if (p_options & MCA_OPTION_SAVE_DIALOG) t_succeeded = GetSaveFileNameW(&t_open_dialog) == TRUE; else t_succeeded = GetOpenFileNameW(&t_open_dialog) == TRUE; if (!t_succeeded) t_result = CommDlgExtendedError(); } if (t_result == FNERR_BUFFERTOOSMALL) t_succeeded = true; if (t_succeeded) { build_paths(&t_value); t_filter_index = t_open_dialog . nFilterIndex; } } if (t_succeeded) { if (p_options & MCA_OPTION_RETURN_FILTER) { // The filter string has the following format: // "<description0>\0<extensions0>\0<description1>\0...\0<extensionsN>\0" // so the n'th filter comes after the 2(n - 1)'th null character uindex_t t_index = 2 * (t_filter_index - 1); uindex_t t_offset = 0; while (t_index--) { /* UNCHECKED */ MCStringFirstIndexOfChar(p_filter, '\0', t_offset, kMCStringOptionCompareExact, t_offset); t_offset++; } uindex_t t_end; t_end = UINDEX_MAX; /* UNCHECKED */ MCStringFirstIndexOfChar(p_filter, '\0', t_offset, kMCStringOptionCompareExact, t_end); /* UNCHECKED */ MCStringCopySubstring(p_filter, MCRangeMake(t_offset, t_end-t_offset), r_result); } t_result = 0; r_value = MCValueRetain(*t_value); } else r_result = MCValueRetain(MCNameGetString(MCN_cancel)); waitonbutton(); return t_result; }
void MCPickExecPickOptionByIndex(MCExecContext &ctxt, int p_chunk_type, MCStringRef *p_option_lists, uindex_t p_option_list_count, uindex_t *p_initial_indices, uindex_t p_indices_count, bool p_use_hilite_type, bool p_use_picker, bool p_use_cancel, bool p_use_done, MCRectangle p_button_rect) { MCAutoArray<MCPickList> t_pick_lists; char_t t_delimiter; switch ((MCChunkType)p_chunk_type) { // No access to the line/item delimiter set in the handler from the mobile-specific functions/commands // so following the old engine default values for them case kMCChunkTypeItem: t_delimiter = ','; break; case kMCChunkTypeWord: case kMCChunkTypeLine: t_delimiter = '\n'; break; default: MCUnreachable(); } uindex_t t_old_offset = 0; uindex_t t_new_offset = 0; bool t_success; t_success = true; for (uindex_t i = 0; i < p_option_list_count; i++) { MCStringRef t_option; MCPickList t_pick_list; MCAutoArray<MCStringRef> t_options; t_old_offset = 0; while (t_success && MCStringFirstIndexOfChar(p_option_lists[i], t_delimiter, t_old_offset, kMCCompareCaseless, t_new_offset)) { t_success = MCStringCopySubstring(p_option_lists[i], MCRangeMakeMinMax(t_old_offset, t_new_offset), t_option); if (t_success) t_options . Push(t_option); t_old_offset = t_new_offset + 1; } // Append the remaining part of the options t_success = MCStringCopySubstring(p_option_lists[i], MCRangeMakeMinMax(t_old_offset, MCStringGetLength(p_option_lists[i])), t_option); if (t_success) t_options . Push(t_option); t_options . Take(t_pick_list . options, t_pick_list . option_count); t_pick_list . initial = p_initial_indices[i]; t_pick_lists . Push(t_pick_list); } bool t_cancelled; uindex_t *t_result; uindex_t t_result_count = 0; // Open the picker and allow the user to select the options if (t_success) t_success = MCSystemPickOption(t_pick_lists . Ptr(), t_pick_lists . Size(), t_result, t_result_count, p_use_hilite_type, p_use_picker, p_use_cancel, p_use_done, t_cancelled, p_button_rect); ctxt.SetTheResultToEmpty(); if (t_success) { if (t_cancelled) { // HC-2012-02-15 [[ BUG 9999 ]] Picker should return 0 if cancel was selected. ctxt . SetTheResultToNumber(0); } else { MCAutoListRef t_indices; t_success = MCListCreateMutable(',', &t_indices); for (uindex_t i = 0; i < t_result_count && t_success; i++) { MCAutoStringRef t_index; t_success = MCStringFormat(&t_index, "%u", t_result[i]); if (t_success) t_success = MCListAppend(*t_indices, *t_index); } MCAutoStringRef t_string; /* UNCHECKED */ MCListCopyAsString(*t_indices, &t_string); ctxt . SetTheResultToValue(*t_string); } } // Free memory for (uindex_t i = 0; i < t_pick_lists . Size(); i++) for (uindex_t j = 0; j < t_pick_lists[i] . option_count; j++) MCValueRelease(t_pick_lists[i] . options[j]); }
static MCStringRef windows_convert_time_format(MCStringRef p_format) { MCStringRef t_output; MCStringCreateMutable(0, t_output); uindex_t t_offset = 0; while (t_offset < MCStringGetLength(p_format)) { unichar_t t_char; t_char = MCStringGetCharAtIndex(p_format, t_offset++); if (t_char == '\'') { // Copy quoted strings to the output with no conversion while ((t_char = MCStringGetCharAtIndex(p_format, t_offset++)) != '\'') MCStringAppendChar(t_output, t_char); } else { // Is this a day/month/year specifier? if (t_char == 'h' || t_char == 'H' || t_char == 'm' || t_char == 's' || t_char == 't') { // Count the number of consecutive identical characters unichar_t t_want = t_char; int t_count = 1; while ((t_char = MCStringGetCharAtIndex(p_format, t_offset)) == t_want) { t_count++; t_offset++; } // Append the correct formatting instruction switch (t_want) { case 'h': if (t_count == 1) MCStringAppendFormat(t_output, "%%#I"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%I"); break; case 'H': if (t_count == 1) MCStringAppendFormat(t_output, "%%#H"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%H"); break; case 'm': if (t_count == 1) MCStringAppendFormat(t_output, "%%#M"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%M"); break; case 's': if (t_count == 1) MCStringAppendFormat(t_output, "%%#S"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%S"); break; case 't': MCStringAppendFormat(t_output, "%%p"); } } else { // Unknown character, copy it to the output MCStringAppendChar(t_output, t_char); } } } MCValueRelease(p_format); return t_output; }
static MCStringRef windows_convert_date_format(MCStringRef p_format) { MCStringRef t_output; MCStringCreateMutable(0, t_output); uindex_t t_offset = 0; while (t_offset < MCStringGetLength(p_format)) { unichar_t t_char; t_char = MCStringGetCharAtIndex(p_format, t_offset++); if (t_char == '\'') { // Copy quoted strings to the output with no conversion while ((t_char = MCStringGetCharAtIndex(p_format, t_offset++)) != '\'') MCStringAppendChar(t_output, t_char); } else { // Is this a day/month/year specifier? if (t_char == 'd' || t_char == 'M' || t_char == 'y') { // Count the number of consecutive identical characters unichar_t t_want = t_char; int t_count = 1; while (MCStringGetCharAtIndex(p_format, t_offset) == t_want) { t_count++; t_offset++; } // Append the correct formatting instruction switch (t_char) { case 'd': if (t_count == 1) MCStringAppendFormat(t_output, "%%#d"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%d"); else if (t_count == 3) MCStringAppendFormat(t_output, "%%a"); else if (t_count == 4) MCStringAppendFormat(t_output, "%%A"); break; case 'M': if (t_count == 1) MCStringAppendFormat(t_output, "%%#m"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%m"); else if (t_count == 3) MCStringAppendFormat(t_output, "%%b"); else if (t_count == 4) MCStringAppendFormat(t_output, "%%B"); break; case 'y': if (t_count == 1) MCStringAppendFormat(t_output, "%%#y"); else if (t_count == 2) MCStringAppendFormat(t_output, "%%y"); else if (t_count == 4) MCStringAppendFormat(t_output, "%%Y"); break; } } else { // Unknown character, copy it to the output MCStringAppendChar(t_output, t_char); } } } MCValueRelease(p_format); return t_output; }