/* Test al_ustr_get on invalid sequences. */ static void t22(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Empty string. */ al_set_errno(0); CHECK(al_ustr_get(al_ustr_empty_string(), 0) < 0); CHECK(al_get_errno() == ERANGE); /* 5-byte sequence. */ us = al_ref_cstr(&info, "\xf8\x88\x80\x80\x80"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); /* Start in trail byte. */ us = al_ref_cstr(&info, "ð"); al_set_errno(0); CHECK(al_ustr_get(us, 1) < 0); CHECK(al_get_errno() == EILSEQ); /* Truncated 3-byte sequence. */ us = al_ref_cstr(&info, "\xEF\xBF"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); }
/* Test al_ustr_get. */ static void t21(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; us = al_ref_buffer(&info, "", 1); CHECK(al_ustr_get(us, 0) == 0); us = al_ref_cstr(&info, "\x7f"); CHECK(al_ustr_get(us, 0) == 0x7f); us = al_ref_cstr(&info, "\xC2\x80"); CHECK(al_ustr_get(us, 0) == 0x80); us = al_ref_cstr(&info, "\xDF\xBf"); CHECK(al_ustr_get(us, 0) == 0x7ff); us = al_ref_cstr(&info, "\xE0\xA0\x80"); CHECK(al_ustr_get(us, 0) == 0x800); us = al_ref_cstr(&info, "\xEF\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0xffff); us = al_ref_cstr(&info, "\xF0\x90\x80\x80"); CHECK(al_ustr_get(us, 0) == 0x010000); us = al_ref_cstr(&info, "\xF4\x8F\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0x10ffff); }
/* Function: al_ustr_find_set */ int al_ustr_find_set(const ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *accept) { int rc; int32_t c, d; int pos; int set_pos; /* Fast path for ASCII characters. */ if (all_ascii(accept)) { rc = _al_binchr(us, start_pos, accept); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Non-ASCII. */ pos = 0; while ((c = al_ustr_get(us, pos)) != -1) { if (c == -2) { /* Invalid byte sequence. */ pos++; continue; } set_pos = 0; while ((d = al_ustr_get_next(accept, &set_pos)) != -1) { if (c == d) return pos; } pos += al_utf8_width(c); } return -1; }
/* Function: al_ustr_set_chr */ size_t al_ustr_set_chr(ALLEGRO_USTR *us, int start_pos, int32_t c) { int32_t oldc; size_t oldw; size_t neww; int rc; oldc = al_ustr_get(us, start_pos); if (oldc == -2) return 0; oldw = al_utf8_width(oldc); neww = al_utf8_width(c); if (neww == 0) return 0; if (oldw > neww) rc = _al_bdelete(us, start_pos, oldw - neww); else if (neww > oldw) rc = _al_binsertch(us, start_pos, neww - oldw, '\0'); else rc = _AL_BSTR_OK; if (rc == _AL_BSTR_OK) return al_utf8_encode(_al_bdataofs(us, start_pos), c); else return 0; }
//return the new start int wz_find_eol(ALLEGRO_USTR* text, ALLEGRO_FONT* font, float max_width, int start, int* end) { int a, b; int first = 1; int last = 0; a = start; while(1) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR* token; float len; /* Find the end of current token */ b = al_ustr_find_set_cstr(text, a, "\t\n "); if(b == -1) //found nothing { b = al_ustr_size(text); //this is the last whole word last = 1; } /* Check to see if the token fits */ token = al_ref_ustr(&info, text, start, b); len = al_get_ustr_width(font, token); if (len < max_width || first) { if(last) { *end = b + 1; return -1; } } else //we return the last num { *end = a - 1; return a; } /* Check what character we found */ { int character = al_ustr_get(text, b); if(character == '\n') { *end = b; return b + 1; } } a = b + 1; first = 0; } }
/* Function: al_ustr_prev_get */ int32_t al_ustr_prev_get(const ALLEGRO_USTR *us, int *pos) { if (al_ustr_prev(us, pos)) { return al_ustr_get(us, *pos); } /* Past beginning. */ return -1; }
/* Function: al_ustr_remove_chr */ bool al_ustr_remove_chr(ALLEGRO_USTR *us, int pos) { int32_t c; size_t w; c = al_ustr_get(us, pos); if (c < 0) return false; w = al_utf8_width(c); return _al_bdelete(us, pos, w) == _AL_BSTR_OK; }
static ALLEGRO_USTR *create_filter_string(const ALLEGRO_USTR *patterns) { ALLEGRO_USTR *filter = al_ustr_new(""); bool filter_all = false; int start, end; if (0 == strcmp(al_cstr(patterns), "*.*")) { filter_all = true; } else { al_ustr_append_cstr(filter, "All Supported Files"); al_ustr_append_chr(filter, '\0'); start = al_ustr_size(filter); al_ustr_append(filter, patterns); /* Remove all instances of "*.*", which will be added separately. */ for (;;) { int pos = al_ustr_find_cstr(filter, start, "*.*;"); if (pos == -1) break; if (pos == start || al_ustr_get(filter, pos - 1) == ';') { filter_all = true; al_ustr_remove_range(filter, pos, pos + 4); start = pos; } else { start = pos + 4; } } while (al_ustr_has_suffix_cstr(filter, ";*.*")) { filter_all = true; end = al_ustr_size(filter); al_ustr_remove_range(filter, end - 4, end); } al_ustr_append_chr(filter, '\0'); } if (filter_all) { al_ustr_append_cstr(filter, "All Files"); al_ustr_append_chr(filter, '\0'); al_ustr_append_cstr(filter, "*.*"); al_ustr_append_chr(filter, '\0'); } al_ustr_append_chr(filter, '\0'); return filter; }
/* Function: al_ustr_get_next */ int32_t al_ustr_get_next(const ALLEGRO_USTR *us, int *pos) { int32_t c = al_ustr_get(us, *pos); if (c >= 0) { (*pos) += al_utf8_width(c); return c; } if (c == -1) { /* Past end. */ return c; } /* Some invalid byte sequence. */ al_ustr_next(us, pos); return c; }
static int ustr_at(ALLEGRO_USTR *string, int index) { return al_ustr_get(string, al_ustr_offset(string, index)); }
/* _al_xwin_keyboard_handler: * Keyboard "interrupt" handler. */ void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display) { int keycode; if (!xkeyboard_installed) return; keycode = keycode_to_scancode[event->keycode]; if (keycode == -1) keycode = find_unknown_key_assignment(event->keycode); update_shifts(event); /* Special case the pause key. */ if (keycode == ALLEGRO_KEY_PAUSE) { /* Allegro ignore's releasing of the pause key. */ if (event->type == KeyRelease) return; if (pause_key) { event->type = KeyRelease; pause_key = 0; } else { pause_key = 1; } } if (event->type == KeyPress) { /* Key pressed. */ int len; char buffer[16]; int unicode = 0; int filtered = 0; #if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING) if (xic) { len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL); } else #endif { /* XLookupString is supposed to only use ASCII. */ len = XLookupString(event, buffer, sizeof buffer, NULL, NULL); } buffer[len] = '\0'; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *ustr = al_ref_cstr(&info, buffer); unicode = al_ustr_get(ustr, 0); if (unicode < 0) unicode = 0; #ifdef ALLEGRO_XWINDOWS_WITH_XIM ALLEGRO_DISPLAY_XGLX *glx = (void *)display; filtered = XFilterEvent((XEvent *)event, glx->window); #endif if (keycode || unicode) { handle_key_press(keycode, unicode, filtered, _key_shifts, display); } } else { /* Key release. */ /* HACK: * Detect key repeat by looking forward to see if this release is * followed by a press event, in which case we assume that this release * event was generated in response to that key press event. Events are * simultaneous if they are separated by less than 4 ms (a value that * worked well on one machine where this hack was needed). * * This is unnecessary on systems where XkbSetDetectableAutorepeat works. */ if (XPending(event->display) > 0) { ALLEGRO_KEY_REPEAT_DATA d; XEvent dummy; d.event = event; d.found = false; XCheckIfEvent(event->display, &dummy, check_for_repeat, (XPointer)&d); if (d.found) { return; } } handle_key_release(keycode, display); } }
/* parse_path_string: * * Parse a path string according to the following grammar. The last * component, if it is not followed by a directory separator, is interpreted * as the filename component, unless it is "." or "..". * * GRAMMAR * * path ::= "//" c+ "/" nonlast [Windows only] * | c ":" nonlast [Windows only] * | nonlast * * nonlast ::= c* "/" nonlast * | last * * last ::= "." * | ".." * | filename * * filename ::= c* [but not "." and ".."] * * c ::= any character but '/' */ static bool parse_path_string(const ALLEGRO_USTR *str, ALLEGRO_PATH *path) { ALLEGRO_USTR_INFO dot_info; ALLEGRO_USTR_INFO dotdot_info; const ALLEGRO_USTR * dot = al_ref_cstr(&dot_info, "."); const ALLEGRO_USTR * dotdot = al_ref_cstr(&dotdot_info, ".."); ALLEGRO_USTR *piece = al_ustr_new(""); int pos = 0; bool on_windows; /* We compile the drive handling code on non-Windows platforms to prevent * it becoming broken. */ #ifdef ALLEGRO_WINDOWS on_windows = true; #else on_windows = false; #endif if (on_windows) { /* UNC \\server\share name */ if (al_ustr_has_prefix_cstr(str, "//")) { int slash = al_ustr_find_chr(str, 2, '/'); if (slash == -1 || slash == 2) { /* Missing slash or server component is empty. */ goto Error; } al_ustr_assign_substr(path->drive, str, pos, slash); pos = slash + 1; } else { /* Drive letter. */ int colon = al_ustr_offset(str, 1); if (colon > -1 && al_ustr_get(str, colon) == ':') { /* Include the colon in the drive string. */ al_ustr_assign_substr(path->drive, str, 0, colon + 1); pos = colon + 1; } } } for (;;) { int slash = al_ustr_find_chr(str, pos, '/'); if (slash == -1) { /* Last component. */ al_ustr_assign_substr(piece, str, pos, al_ustr_size(str)); if (al_ustr_equal(piece, dot) || al_ustr_equal(piece, dotdot)) { al_append_path_component(path, al_cstr(piece)); } else { /* This might be an empty string, but that's okay. */ al_ustr_assign(path->filename, piece); } break; } /* Non-last component. */ al_ustr_assign_substr(piece, str, pos, slash); al_append_path_component(path, al_cstr(piece)); pos = slash + 1; } al_ustr_free(piece); return true; Error: al_ustr_free(piece); return false; }
/* [nd_gtk thread] */ static gboolean create_gtk_file_dialog(gpointer data) { GTK_FILE_DIALOG_MESSAGE *msg = data; ALLEGRO_DISPLAY *display = msg->display; ALLEGRO_NATIVE_DIALOG *fd = msg->dialog; bool save = fd->flags & ALLEGRO_FILECHOOSER_SAVE; gint result; GtkWidget *window; window = gtk_file_chooser_dialog_new(al_cstr(fd->title), NULL, save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); _al_gtk_make_transient(display, window); if (fd->fc_initial_path) { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(window), al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP)); } if (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(window), true); /* FIXME: Move all this filter parsing stuff into a common file. */ if (al_ustr_size(fd->fc_patterns) > 0) { GtkFileFilter* filter = gtk_file_filter_new(); int start = 0; int end = 0; bool is_mime_type = false; while (true) { int32_t c = al_ustr_get(fd->fc_patterns, end); if (c < 0 || c == ';') { if (end - start > 0) { ALLEGRO_USTR* pattern = al_ustr_dup_substr(fd->fc_patterns, start, end); if (is_mime_type) { gtk_file_filter_add_mime_type(filter, al_cstr(pattern)); } else { gtk_file_filter_add_pattern(filter, al_cstr(pattern)); } al_ustr_free(pattern); } start = end + 1; is_mime_type = false; } if (c == '/') is_mime_type = true; if (c < 0) break; end += al_utf8_width(c); } gtk_file_filter_set_name(filter, "All supported files"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(window), filter); } result = gtk_dialog_run(GTK_DIALOG(window)); if (result == GTK_RESPONSE_ACCEPT) { GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(window)); int i; GSList* iter; fd->fc_path_count = g_slist_length(filenames); fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); for (i = 0, iter = filenames; i < (int)fd->fc_path_count; i++, iter = g_slist_next(iter)) { fd->fc_paths[i] = al_create_path((const char*)iter->data); g_free(iter->data); } g_slist_free(filenames); } gtk_widget_destroy(window); ASSERT(fd->async_queue); g_async_queue_push(fd->async_queue, ACK_CLOSED); return FALSE; }
/* Get more ideas for tests from * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */ static void t23(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Examples of an overlong ASCII character */ us = al_ref_cstr(&info, "\xc0\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); /* Maximum overlong sequences */ us = al_ref_cstr(&info, "\xc1\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x9f\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x8f\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x87\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x83\xbf\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); /* Overlong representation of the NUL character */ us = al_ref_cstr(&info, "\xc0\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); }