static int str_utf8_isprint (const char *ch) { gunichar uni = g_utf8_get_char_validated (ch, -1); return g_unichar_isprint (uni); }
void s_check_text (const GList *obj_list, SYMCHECK *s_current) { const GList *iter; OBJECT *o_current; gboolean overbar_started, escape, leave_parser; char *message; char *text_string, *ptr; gunichar current_char; for (iter = obj_list; iter != NULL; iter = g_list_next(iter)) { o_current = iter->data; if (o_current->type != OBJ_TEXT) continue; overbar_started = escape = leave_parser = FALSE; text_string = o_current->text->string; for (ptr = text_string; ptr != NULL && !leave_parser; ptr = g_utf8_find_next_char (ptr, NULL)) { current_char = g_utf8_get_char_validated (ptr, -1); /* state machine to interpret the string: * there are two independant state variables overbar_started and escape. */ switch (current_char) { case '\0': /* end of the string */ leave_parser = TRUE; break; case '\\': if (escape == TRUE) { escape = FALSE; } else { escape = TRUE; } break; case '_': if (escape == TRUE) { escape = FALSE; if (overbar_started == TRUE) { overbar_started = FALSE; } else { overbar_started = TRUE; } } break; default: if (escape == TRUE) { message = g_strdup_printf ("Found text with a '\\' in it: consider" " to escape it with '\\\\' [%s]\n", text_string); s_current->warning_messages = g_list_append(s_current->warning_messages, message); s_current->warning_count++; escape = FALSE; } } } if (escape == TRUE) { message = g_strdup_printf ("Found text with a trailing '\': consider to " "escape it with '\\\\' [%s]\n", text_string); s_current->warning_messages = g_list_append(s_current->warning_messages, message); s_current->warning_count++; } if (overbar_started == TRUE) { message = g_strdup_printf ("Found text with unbalanced overbar " "markers '\\_' in it' [%s]\n", text_string); s_current->warning_messages = g_list_append(s_current->warning_messages, message); s_current->warning_count++; } } }
static int str_utf8_isdigit (const char *text) { gunichar uni = g_utf8_get_char_validated (text, -1); return g_unichar_isdigit (uni); }
static gboolean _rox_buffer_looks_like_text (const void *data, const size_t len) { gchar *end; if (g_utf8_validate (data, len, (const gchar**)&end)) { /* g_utf8_validate allows control characters */ int i; for (i = 0; i < len; i++) { unsigned char c = ((const guchar *) data)[i]; if (c < 32 && c != '\r' && c != '\n' && c != '\t') return FALSE; } return TRUE; } else { /* Check whether the string was truncated in the middle of * a valid UTF8 char, or if we really have an invalid * UTF8 string */ gint remaining_bytes = len; remaining_bytes -= (end-((gchar*)data)); if (g_utf8_get_char_validated(end, remaining_bytes) == -2) return TRUE; #if defined(HAVE_WCTYPE_H) && defined (HAVE_MBRTOWC) else { size_t wlen; wchar_t wc; gchar *src, *end; mbstate_t state; src = data; end = data+len; memset (&state, 0, sizeof (state)); while (src < end) { /* Don't allow embedded zeros in textfiles */ if (*src == 0) return FALSE; wlen = mbrtowc(&wc, src, end - src, &state); if (wlen == (size_t)(-1)) { /* Illegal mb sequence */ return FALSE; } if (wlen == (size_t)(-2)) { /* No complete mb char before end * Probably a cut off char which is ok */ return TRUE; } if (wlen == 0) { /* Don't allow embedded zeros in textfiles */ return FALSE; } if (!iswspace (wc) && !iswprint(wc)) { /* Not a printable or whitspace * Probably not a text file */ return FALSE; } src += wlen; } return TRUE; } #endif /* defined(HAVE_WCTYPE_H) && defined (HAVE_MBRTOWC) */ } return FALSE; }
/* utiliti function, that make string valid in utf8 and all characters printable * return width of string too*/ static const struct term_form * str_utf8_make_make_term_form (const char *text, size_t length) { static struct term_form result; gunichar uni; size_t left; char *actual; result.text[0] = '\0'; result.width = 0; result.compose = FALSE; actual = result.text; /* check if text start with combining character, * add space at begin in this case */ if (length != 0 && text[0] != '\0') { uni = g_utf8_get_char_validated (text, -1); if ((uni != (gunichar) (-1)) && (uni != (gunichar) (-2)) && str_unichar_iscombiningmark (uni)) { actual[0] = ' '; actual++; result.width++; result.compose = TRUE; } } while (length != 0 && text[0] != '\0') { uni = g_utf8_get_char_validated (text, -1); if ((uni != (gunichar) (-1)) && (uni != (gunichar) (-2))) { if (g_unichar_isprint (uni)) { left = g_unichar_to_utf8 (uni, actual); actual += left; if (str_unichar_iscombiningmark (uni)) result.compose = TRUE; else { result.width++; if (g_unichar_iswide (uni)) result.width++; } } else { actual[0] = '.'; actual++; result.width++; } text = g_utf8_next_char (text); } else { text++; /*actual[0] = '?'; */ memcpy (actual, replch, strlen (replch)); actual += strlen (replch); result.width++; } if (length != (size_t) (-1)) length--; } actual[0] = '\0'; return &result; }
void mcview_display_hex (WView * view) { const screen_dimen top = view->data_area.top; const screen_dimen left = view->data_area.left; const screen_dimen height = view->data_area.height; const screen_dimen width = view->data_area.width; const int ngroups = view->bytes_per_line / 4; /* 8 characters are used for the file offset, and every hex group * takes 13 characters. Starting at width of 80 columns, the groups * are separated by an extra vertical line. Starting at width of 81, * there is an extra space before the text column. There is always a * mostly empty column on the right, to allow overflowing CJKs. */ const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (width == 80) ? (ngroups - 1) : (ngroups - 1 + 1)); int row; off_t from; mark_t boldflag_byte = MARK_NORMAL; mark_t boldflag_char = MARK_NORMAL; struct hexedit_change_node *curr = view->change_list; #ifdef HAVE_CHARSET int cont_bytes = 0; /* number of continuation bytes remanining from current UTF-8 */ gboolean cjk_right = FALSE; /* whether the second byte of a CJK is to be processed */ #endif /* HAVE_CHARSET */ gboolean utf8_changed = FALSE; /* whether any of the bytes in the UTF-8 were changed */ char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */ mcview_display_clean (view); /* Find the first displayable changed byte */ /* In UTF-8 mode, go back by 1 or maybe 2 lines to handle continuation bytes properly. */ from = view->dpy_start; row = 0; #ifdef HAVE_CHARSET if (view->utf8) { if (from >= view->bytes_per_line) { row--; from -= view->bytes_per_line; } if (view->bytes_per_line == 4 && from >= view->bytes_per_line) { row--; from -= view->bytes_per_line; } } #endif /* HAVE_CHARSET */ while (curr && (curr->offset < from)) { curr = curr->next; } for (; mcview_get_byte (view, from, NULL) && row < (int) height; row++) { screen_dimen col = 0; size_t i; int bytes; /* Number of bytes already printed on the line */ /* Print the hex offset */ if (row >= 0) { g_snprintf (hex_buff, sizeof (hex_buff), "%08" PRIXMAX " ", (uintmax_t) from); widget_move (view, top + row, left); tty_setcolor (VIEW_BOLD_COLOR); for (i = 0; col < width && hex_buff[i] != '\0'; col++, i++) tty_print_char (hex_buff[i]); tty_setcolor (VIEW_NORMAL_COLOR); } for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) { int c; #ifdef HAVE_CHARSET int ch = 0; if (view->utf8) { struct hexedit_change_node *corr = curr; if (cont_bytes != 0) { /* UTF-8 continuation bytes, print a space (with proper attributes)... */ cont_bytes--; ch = ' '; if (cjk_right) { /* ... except when it'd wipe out the right half of a CJK, then print nothing */ cjk_right = FALSE; ch = -1; } } else { int j; gchar utf8buf[UTF8_CHAR_LEN + 1]; int res; int first_changed = -1; for (j = 0; j < UTF8_CHAR_LEN; j++) { if (mcview_get_byte (view, from + j, &res)) utf8buf[j] = res; else { utf8buf[j] = '\0'; break; } if (curr != NULL && from + j == curr->offset) { utf8buf[j] = curr->value; if (first_changed == -1) first_changed = j; } if (curr != NULL && from + j >= curr->offset) curr = curr->next; } utf8buf[UTF8_CHAR_LEN] = '\0'; /* Determine the state of the current multibyte char */ ch = g_utf8_get_char_validated (utf8buf, -1); if (ch == -1 || ch == -2) { ch = '.'; } else { gchar *next_ch; next_ch = g_utf8_next_char (utf8buf); cont_bytes = next_ch - utf8buf - 1; if (g_unichar_iswide (ch)) cjk_right = TRUE; } utf8_changed = (first_changed >= 0 && first_changed <= cont_bytes); curr = corr; } } #endif /* HAVE_CHARSET */ /* For negative rows, the only thing we care about is overflowing * UTF-8 continuation bytes which were handled above. */ if (row < 0) { if (curr != NULL && from == curr->offset) curr = curr->next; continue; } if (!mcview_get_byte (view, from, &c)) break; /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && !view->hexview_in_text) { view->cursor_row = row; view->cursor_col = col; } /* Determine the state of the current byte */ boldflag_byte = mcview_hex_calculate_boldflag (view, from, curr, FALSE); boldflag_char = mcview_hex_calculate_boldflag (view, from, curr, utf8_changed); /* Determine the value of the current byte */ if (curr != NULL && from == curr->offset) { c = curr->value; curr = curr->next; } /* Select the color for the hex number */ tty_setcolor (boldflag_byte == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag_byte == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag_byte == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag_byte == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : VIEW_UNDERLINED_COLOR); /* Print the hex number */ widget_move (view, top + row, left + col); if (col < width) { tty_print_char (hex_char[c / 16]); col += 1; } if (col < width) { tty_print_char (hex_char[c % 16]); col += 1; } /* Print the separator */ tty_setcolor (VIEW_NORMAL_COLOR); if (bytes != view->bytes_per_line - 1) { if (col < width) { tty_print_char (' '); col += 1; } /* After every four bytes, print a group separator */ if (bytes % 4 == 3) { if (view->data_area.width >= 80 && col < width) { tty_print_one_vline (TRUE); col += 1; } if (col < width) { tty_print_char (' '); col += 1; } } } /* Select the color for the character; this differs from the * hex color when boldflag == MARK_CURSOR */ tty_setcolor (boldflag_char == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag_char == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag_char == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag_char == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : MARKED_SELECTED_COLOR); #ifdef HAVE_CHARSET if (mc_global.utf8_display) { if (!view->utf8) { c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter); } if (!g_unichar_isprint (c)) c = '.'; } else if (view->utf8) ch = convert_from_utf_to_current_c (ch, view->converter); else #endif { #ifdef HAVE_CHARSET c = convert_to_display_c (c); #endif if (!is_printable (c)) c = '.'; } /* Print corresponding character on the text side */ if (text_start + bytes < width) { widget_move (view, top + row, left + text_start + bytes); #ifdef HAVE_CHARSET if (view->utf8) tty_print_anychar (ch); else #endif tty_print_char (c); } /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && view->hexview_in_text) { view->cursor_row = row; view->cursor_col = text_start + bytes; } } } /* Be polite to the other functions */ tty_setcolor (VIEW_NORMAL_COLOR); mcview_place_cursor (view); view->dpy_end = from; }
static void handle_input() { /* Mapping from get_wch() to input_key_t: * KEY_CODE_YES -> KEY(code) * KEY_CODE_NO: * char == 127 -> KEY(KEY_BACKSPACE) * char <= 31 -> CTRL(char) * !'^[' -> CHAR(char) * ('^[', !) -> KEY(KEY_ESCAPE) * ('^[', !CHAR) -> ignore both characters (1) * ('^[', CHAR && '[') -> ignore both characters and the character after that (2) * ('^[', CHAR && !'[') -> ALT(second char) * * 1. this is something like ctrl+alt+X, which we won't use * 2. these codes indicate a 'Key' that somehow wasn't captured with * KEY_CODE_YES. We won't attempt to interpret these ourselves. * * There are still several unhandled issues: * - Ncurses does not catch all key codes, and there is no way of knowing how * many bytes a key code spans. Things like ^[[1;3C won't be handled correctly. :-( * - Ncurses can actually return key codes > KEY_MAX, but does not provide * any mechanism for figuring out which key it actually was. * - It may be useful to use define_key() for some special (and common) codes * - Modifier keys will always be a problem. Most alt+key things work, except * for those that may start a control code. alt+[ is a famous one, but * there are others (like alt+O on my system). This is system-dependent, * and again we have no way of knowing these things. (except perhaps by * reading termcap entries on our own?) */ guint64 key; char buf[9]; int r; wint_t code; int lastesc = 0, curignore = 0; while((r = get_wch(&code)) != ERR) { if(curignore) { curignore = 0; continue; } // we use SIGWINCH, so KEY_RESIZE can be ignored if(r == KEY_CODE_YES && code == KEY_RESIZE) continue; // backspace (outside of an escape sequence) is often sent as DEL control character, correct this if(!lastesc && r != KEY_CODE_YES && code == 127) { r = KEY_CODE_YES; code = KEY_BACKSPACE; } // backspace inside an escape sequence is also possible, convert the other way around if(lastesc && r == KEY_CODE_YES && code == KEY_BACKSPACE) { r = !KEY_CODE_YES; code = 127; } key = r == KEY_CODE_YES ? INPT_KEY(code) : code == 27 ? INPT_ALT(0) : code <= 31 ? INPT_CTRL(ctrl_to_ascii(code)) : INPT_CHAR(code); // convert wchar_t into gunichar if(INPT_TYPE(key) == 1) { if((r = wctomb(buf, code)) < 0) g_warning("Cannot encode character 0x%X", code); buf[r] = 0; key = INPT_CHAR(g_utf8_get_char_validated(buf, -1)); if(INPT_CODE(key) == (gunichar)-1 || INPT_CODE(key) == (gunichar)-2) { g_warning("Invalid UTF-8 sequence in keyboard input. Are you sure you are running a UTF-8 locale?"); continue; } } // check for escape sequence if(lastesc) { lastesc = 0; if(INPT_TYPE(key) != 1) continue; if(INPT_CODE(key) == '[') { curignore = 1; continue; } key |= (guint64)3<<32; // a not very nice way of saying "turn this key into a INPT_ALT" ui_input(key); continue; } if(INPT_TYPE(key) == 3) { lastesc = 1; continue; } ui_input(key); } if(lastesc) ui_input(INPT_KEY(KEY_ESCAPE)); ui_draw(); }
/************************************************************************** Refresh info label **************************************************************************/ void update_info_label(void) { GtkWidget *label; const struct player *pplayer = client.conn.playing; label = gtk_frame_get_label_widget(GTK_FRAME(main_frame_civ_name)); if (pplayer != NULL) { const gchar *name; gunichar c; /* Capitalize the first character of the translated nation * plural name so that the frame label looks good. */ name = nation_plural_for_player(pplayer); c = g_utf8_get_char_validated(name, -1); if ((gunichar) -1 != c && (gunichar) -2 != c) { gchar nation[MAX_LEN_NAME]; gchar *next; gint len; len = g_unichar_to_utf8(g_unichar_toupper(c), nation); nation[len] = '\0'; next = g_utf8_find_next_char(name, NULL); if (NULL != next) { sz_strlcat(nation, next); } gtk_label_set_text(GTK_LABEL(label), nation); } else { gtk_label_set_text(GTK_LABEL(label), name); } } else { gtk_label_set_text(GTK_LABEL(label), "-"); } gtk_label_set_text(GTK_LABEL(main_label_info), get_info_label_text(!gui_gtk3_small_display_layout)); set_indicator_icons(client_research_sprite(), client_warming_sprite(), client_cooling_sprite(), client_government_sprite()); if (NULL != client.conn.playing) { int d = 0; for (; d < client.conn.playing->economic.luxury /10; d++) { struct sprite *sprite = get_tax_sprite(tileset, O_LUXURY); gtk_pixcomm_set_from_sprite(GTK_PIXCOMM(econ_label[d]), sprite); } for (; d < (client.conn.playing->economic.science + client.conn.playing->economic.luxury) / 10; d++) { struct sprite *sprite = get_tax_sprite(tileset, O_SCIENCE); gtk_pixcomm_set_from_sprite(GTK_PIXCOMM(econ_label[d]), sprite); } for (; d < 10; d++) { struct sprite *sprite = get_tax_sprite(tileset, O_GOLD); gtk_pixcomm_set_from_sprite(GTK_PIXCOMM(econ_label[d]), sprite); } } update_timeout_label(); /* update tooltips. */ gtk_widget_set_tooltip_text(econ_ebox, _("Shows your current luxury/science/tax rates; " "click to toggle them.")); gtk_widget_set_tooltip_text(bulb_ebox, get_bulb_tooltip()); gtk_widget_set_tooltip_text(sun_ebox, get_global_warming_tooltip()); gtk_widget_set_tooltip_text(flake_ebox, get_nuclear_winter_tooltip()); gtk_widget_set_tooltip_text(government_ebox, get_government_tooltip()); }
static int parse_file (FILE * in, FILE * out, IspellMode_t mode, int countLines, gchar *dictionary) { EnchantBroker * broker; EnchantDict * dict; GString * str, * word = NULL; GSList * tokens, *token_ptr; gchar * lang; size_t pos, lineCount = 0; gboolean was_last_line = FALSE, corrected_something = FALSE, terse_mode = FALSE; if (mode == MODE_A) print_version (out); if (dictionary) { lang = convert_language_code (dictionary); } else { lang = enchant_get_user_language(); if(!lang) return 1; } /* Enchant will get rid of useless trailing garbage like de_DE@euro or de_DE.ISO-8859-15 */ broker = enchant_broker_init (); dict = enchant_broker_request_dict (broker, lang); if (!dict) { fprintf (stderr, "Couldn't create a dictionary for %s\n", lang); g_free (lang); enchant_broker_free (broker); return 1; } g_free (lang); str = g_string_new (NULL); while (!was_last_line) { gboolean mode_A_no_command = FALSE; was_last_line = consume_line (in, str); if (countLines) lineCount++; if (str->len) { corrected_something = FALSE; if (mode == MODE_A) { switch (*str->str) { case '&': /* Insert uncapitalised in personal word list */ if (str->len > 1) { gunichar c = g_utf8_get_char_validated(str->str + 1, str->len); if (c > 0) { str = g_string_erase(str, 1, g_utf8_next_char(str->str + 1) - (str->str + 1)); g_string_insert_unichar(str, 1, g_unichar_tolower(c)); } } /* FALLTHROUGH */ case '*': /* Insert in personal word list */ if (str->len == 1) goto empty_word; enchant_dict_add(dict, str->str + 1, -1); break; case '@': /* Accept for this session */ if (str->len == 1) goto empty_word; enchant_dict_add_to_session(dict, str->str + 1, -1); break; case '%': /* Exit terse mode */ terse_mode = FALSE; break; case '!': /* Enter terse mode */ terse_mode = TRUE; break; /* Ignore these commands */ case '#': /* Save personal word list (enchant does this automatically) */ case '+': /* LaTeX mode */ case '-': /* nroff mode [default] */ case '~': /* change string character type (enchant is fixed to UTF-8) */ case '`': /* Enter verbose-correction mode */ break; case '$': /* Save correction for rest of session [aspell extension] */ { /* Syntax: $$ra <MISSPELLED>,<REPLACEMENT> */ gchar *prefix = "$$ra "; if (g_str_has_prefix(str->str, prefix)) { gchar *comma = g_utf8_strchr(str->str, -1, (gunichar)','); char *mis = str->str + strlen(prefix); char *cor = comma + 1; ssize_t mis_len = comma - mis; ssize_t cor_len = strlen(str->str) - (cor - str->str); enchant_dict_store_replacement(dict, mis, mis_len, cor, cor_len); } } break; case '^': /* ^ is used as prefix to prevent interpretation of original first character as a command */ /* FALLTHROUGH */ default: /* A word or words to check */ mode_A_no_command = TRUE; break; empty_word: fprintf (out, "Error: The word \"\" is invalid. Empty string.\n"); } } if (mode != MODE_A || mode_A_no_command) { token_ptr = tokens = tokenize_line (str); if (tokens == NULL) putc('\n', out); while (tokens != NULL) { corrected_something = TRUE; word = (GString *)tokens->data; tokens = tokens->next; pos = GPOINTER_TO_INT(tokens->data); tokens = tokens->next; if (mode == MODE_A) do_mode_a (out, dict, word, pos, lineCount, terse_mode); else if (mode == MODE_L) do_mode_l (out, dict, word, lineCount); g_string_free(word, TRUE); } if (token_ptr) g_slist_free (token_ptr); } } if (mode == MODE_A && corrected_something) { fwrite ("\n", 1, 1, out); } g_string_truncate (str, 0); fflush (out); } enchant_broker_free_dict (broker, dict); enchant_broker_free (broker); g_string_free (str, TRUE); return 0; }
/* From gcoincoin */ static gchar *strutf8( const gchar *pc, guint uMaxChar ) { gunichar uCode ; guchar b ; gsize uLen ; GString *pString ; guint uChar ; const gchar *pcEnd ; if(( pc == NULL )||( *pc == 0 )) { return NULL ; } if( uMaxChar == 0 ) { uMaxChar = G_MAXUINT ; } uLen = strlen( pc ); pcEnd = &pc[ uLen ]; uChar = 0 ; if( g_utf8_validate( pc, (gssize) uLen, NULL ) ) { const gchar *pcStart = pc ; while(( pc < pcEnd )&&( uChar < uMaxChar )) { pc = g_utf8_next_char(pc); uChar++ ; } return g_strndup( pcStart, pc - pcStart ); } pString = g_string_sized_new( uLen ); while(( pc < pcEnd )&&( uChar < uMaxChar )) { b = (guchar) *pc ; if( b < 128 ) { /* Keep ASCII characters, but remove all control characters * but CR, LF and TAB. */ if(( b > 31 )&&( b != 127 )) { g_string_append_c( pString, b ); } else { switch( b ) { case '\n': case '\r': case '\t': break ; default: b = ' ' ; } g_string_append_c( pString, b ); } pc++ ; } else { uCode = g_utf8_get_char_validated( pc, -1 ); if(( uCode != (gunichar)-1 )&&( uCode != (gunichar)-2 )) { /* Keep a valid UTF-8 character as is */ g_string_append_unichar( pString, uCode ); pc = g_utf8_next_char(pc); } else { /* Consider an invalid byte as an ISO-8859-1 character code. * We get rid of ASCII & ISO-8859-1 control characters. */ if(( b > 0x1F )&&( b < 0x7F )) { /* ASCII characters, excluding control characters */ g_string_append_c( pString, b ); } else if( b > 0x9F ) { /* ISO-8859-1 character, excluding control character (0x7F-0x9F) */ g_string_append_unichar( pString, (gunichar)b ); } else { g_string_append_c( pString, ' ' ); } pc++ ; } } uChar++ ; } #ifdef DEBUG g_assert( g_utf8_validate( pString->str, -1, NULL ) ); #endif return g_string_free( pString, FALSE ); }
/* Copied from tracker/src/libtracker-fts/tracker-parser-glib.c under the GPL * Originally written by Aleksander Morgado <*****@*****.**> */ char * shell_util_normalize_casefold_and_unaccent (const char *str) { char *tmp; gsize i = 0, j = 0, ilen; if (str == NULL) return NULL; /* Get the NFKD-normalized and casefolded string */ tmp = shell_util_normalize_and_casefold (str); ilen = strlen (tmp); while (i < ilen) { gunichar unichar; gchar *next_utf8; gint utf8_len; /* Get next character of the word as UCS4 */ unichar = g_utf8_get_char_validated (&tmp[i], -1); /* Invalid UTF-8 character or end of original string. */ if (unichar == (gunichar) -1 || unichar == (gunichar) -2) { break; } /* Find next UTF-8 character */ next_utf8 = g_utf8_next_char (&tmp[i]); utf8_len = next_utf8 - &tmp[i]; if (IS_CDM_UCS4 ((guint32) unichar)) { /* If the given unichar is a combining diacritical mark, * just update the original index, not the output one */ i += utf8_len; continue; } /* If already found a previous combining * diacritical mark, indexes are different so * need to copy characters. As output and input * buffers may overlap, need to use memmove * instead of memcpy */ if (i != j) { memmove (&tmp[j], &tmp[i], utf8_len); } /* Update both indexes */ i += utf8_len; j += utf8_len; } /* Force proper string end */ tmp[j] = '\0'; return tmp; }
int mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * result) { gchar *str = NULL; int res = -1; gunichar ch; gchar *next_ch = NULL; gchar utf8buf[UTF8_CHAR_LEN + 1]; *char_width = 0; *result = FALSE; switch (view->datasource) { case DS_STDIO_PIPE: case DS_VFS_PIPE: str = mcview_get_ptr_growing_buffer (view, byte_index); break; case DS_FILE: str = mcview_get_ptr_file (view, byte_index); break; case DS_STRING: str = mcview_get_ptr_string (view, byte_index); break; case DS_NONE: break; } if (str == NULL) return 0; res = g_utf8_get_char_validated (str, -1); if (res < 0) { /* Retry with explicit bytes to make sure it's not a buffer boundary */ int i; for (i = 0; i < UTF8_CHAR_LEN; i++) { if (mcview_get_byte (view, byte_index + i, &res)) utf8buf[i] = res; else { utf8buf[i] = '\0'; break; } } utf8buf[UTF8_CHAR_LEN] = '\0'; str = utf8buf; res = g_utf8_get_char_validated (str, -1); } if (res < 0) { ch = *str; *char_width = 1; } else { ch = res; /* Calculate UTF-8 char width */ next_ch = g_utf8_next_char (str); if (next_ch) *char_width = next_ch - str; else return 0; } *result = TRUE; return ch; }
static int key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2, struct session *sess) { int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, prefix_len, skip_len = 0; gboolean is_nick = FALSE, is_cmd = FALSE, found = FALSE, has_nick_prefix = FALSE; char ent[CHANLEN], *postfix = NULL, *result, *ch; GList *list = NULL, *tmp_list = NULL; const char *text; GCompletion *gcomp = NULL; GString *buf; /* force the IM Context to reset */ SPELL_ENTRY_SET_EDITABLE (t, FALSE); SPELL_ENTRY_SET_EDITABLE (t, TRUE); text = SPELL_ENTRY_GET_TEXT (t); if (text[0] == 0) return 1; len = g_utf8_strlen (text, -1); /* must be null terminated */ cursor_pos = SPELL_ENTRY_GET_POS (t); /* handle "nick: " or "nick " or "#channel "*/ ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos)); if (ch && ch[0] == ' ') { skip_len++; ch = g_utf8_find_prev_char(text, ch); if (!ch) return 2; cursor_pos = g_utf8_pointer_to_offset(text, ch); if (cursor_pos && (g_utf8_get_char_validated(ch, -1) == ':' || g_utf8_get_char_validated(ch, -1) == ',' || g_utf8_get_char_validated (ch, -1) == g_utf8_get_char_validated (prefs.hex_completion_suffix, -1))) { skip_len++; } else cursor_pos = g_utf8_pointer_to_offset(text, g_utf8_offset_to_pointer(ch, 1)); } comp = skip_len; /* store the text following the cursor for reinsertion later */ if ((cursor_pos + skip_len) < len) postfix = g_utf8_offset_to_pointer(text, cursor_pos + skip_len); for (ent_start = cursor_pos; ; --ent_start) { if (ent_start == 0) break; ch = g_utf8_offset_to_pointer(text, ent_start - 1); if (ch && ch[0] == ' ') break; } if (ent_start == 0 && text[0] == prefs.hex_input_command_char[0]) { ent_start++; is_cmd = TRUE; } else if (strchr (sess->server->chantypes, text[ent_start]) == NULL) { is_nick = TRUE; if (strchr (sess->server->nick_prefixes, text[ent_start]) != NULL) { if (ent_start == 0) has_nick_prefix = TRUE; ent_start++; } } prefix_len = ent_start; elen = cursor_pos - ent_start; g_utf8_strncpy (ent, g_utf8_offset_to_pointer (text, prefix_len), elen); if (sess->type == SESS_DIALOG && is_nick) { /* tab in a dialog completes the other person's name */ if (rfc_ncasecmp (sess->channel, ent, elen) == 0) { result = sess->channel; is_nick = FALSE; } else return 2; } else { if (is_nick) { gcomp = g_completion_new((GCompletionFunc)gcomp_nick_func); tmp_list = userlist_double_list(sess); /* create a temp list so we can free the memory */ if (prefs.hex_completion_sort == 1) /* sort in last-talk order? */ tmp_list = g_list_sort (tmp_list, (void *)talked_recent_cmp); } else { gcomp = g_completion_new (NULL); if (is_cmd) { tmp_list = cmdlist_double_list (command_list); for(i = 0; xc_cmds[i].name != NULL ; i++) { tmp_list = g_list_prepend (tmp_list, xc_cmds[i].name); } tmp_list = plugin_command_list(tmp_list); } else tmp_list = chanlist_double_list (sess_list); } tmp_list = g_list_reverse(tmp_list); /* make the comp entries turn up in the right order */ g_completion_set_compare (gcomp, (GCompletionStrncmpFunc)rfc_ncasecmp); if (tmp_list) { g_completion_add_items (gcomp, tmp_list); g_list_free (tmp_list); } if (comp && !(rfc_ncasecmp(old_gcomp.data, ent, old_gcomp.elen) == 0)) { key_action_tab_clean (); comp = 0; } list = g_completion_complete_utf8 (gcomp, comp ? old_gcomp.data : ent, &result); if (result == NULL) /* No matches found */ { g_completion_free(gcomp); return 2; } if (comp) /* existing completion */ { while(list) /* find the current entry */ { if(rfc_ncasecmp(list->data, ent, elen) == 0) { found = TRUE; break; } list = list->next; } if (found) { if (!(d1 && d1[0])) /* not holding down shift */ { if (g_list_next(list) == NULL) list = g_list_first(list); else list = g_list_next(list); } else { if (g_list_previous(list) == NULL) list = g_list_last(list); else list = g_list_previous(list); } g_free(result); result = (char*)list->data; } else { g_free(result); g_completion_free(gcomp); return 2; } } else { strcpy(old_gcomp.data, ent); old_gcomp.elen = elen; /* Get the first nick and put out the data for future nickcompletes */ if (prefs.hex_completion_amount > 0 && g_list_length (list) <= (guint) prefs.hex_completion_amount) { g_free(result); result = (char*)list->data; } else { /* bash style completion */ if (g_list_next(list) != NULL) { buf = g_string_sized_new (MAX(COMP_BUF, len + NICKLEN)); if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */ { if (prefix_len) g_string_append_len (buf, text, offset_to_len (text, prefix_len)); g_string_append (buf, result); cursor_pos = buf->len; g_free(result); if (postfix) { g_string_append_c (buf, ' '); g_string_append (buf, postfix); } SPELL_ENTRY_SET_TEXT (t, buf->str); SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos)); g_string_erase (buf, 0, -1); } else g_free(result); while (list) { len = buf->len; elen = strlen (list->data); /* next item to add */ if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */ { PrintText (sess, buf->str); g_string_erase (buf, 0, -1); } g_string_append (buf, (char*)list->data); g_string_append_c (buf, ' '); list = list->next; } PrintText (sess, buf->str); g_completion_free(gcomp); g_string_free (buf, TRUE); return 2; } /* Only one matching entry */ g_free(result); result = list->data; } } } if(result) { buf = g_string_sized_new (len + NICKLEN); if (prefix_len) g_string_append_len (buf, text, offset_to_len (text, prefix_len)); g_string_append (buf, result); if((!prefix_len || has_nick_prefix) && is_nick && prefs.hex_completion_suffix[0] != '\0') g_string_append_unichar (buf, g_utf8_get_char_validated (prefs.hex_completion_suffix, -1)); g_string_append_c (buf, ' '); cursor_pos = buf->len; if (postfix) g_string_append (buf, postfix); SPELL_ENTRY_SET_TEXT (t, buf->str); SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos)); g_string_free (buf, TRUE); } if (gcomp) g_completion_free(gcomp); return 2; }
/* FIXME: for our purposes it's probably enough to just check for the sync * marker - we just want to know if it's a header frame or not */ static gboolean gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size, gint64 * last_sample_num) { guint headerlen; guint sr_from_end = 0; /* can be 0, 8 or 16 */ guint bs_from_end = 0; /* can be 0, 8 or 16 */ guint32 val = 0; guint8 bs, sr, ca, ss, pb; if (size < 10) return FALSE; /* sync */ if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8) return FALSE; if (data[1] & 1) { GST_WARNING_OBJECT (flacdec, "Variable block size FLAC unsupported"); return FALSE; } bs = (data[2] & 0xF0) >> 4; /* blocksize marker */ sr = (data[2] & 0x0F); /* samplerate marker */ ca = (data[3] & 0xF0) >> 4; /* channel assignment */ ss = (data[3] & 0x0F) >> 1; /* sample size marker */ pb = (data[3] & 0x01); /* padding bit */ GST_LOG_OBJECT (flacdec, "got sync, bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", bs, sr, ca, ss, pb); if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) { return FALSE; } /* read block size from end of header? */ if (bs == 6) bs_from_end = 8; else if (bs == 7) bs_from_end = 16; /* read sample rate from end of header? */ if (sr == 0x0C) sr_from_end = 8; else if (sr == 0x0D || sr == 0x0E) sr_from_end = 16; val = data[4]; /* This is slightly faster than a loop */ if (!(val & 0x80)) { val = 0; } else if ((val & 0xc0) && !(val & 0x20)) { val = 1; } else if ((val & 0xe0) && !(val & 0x10)) { val = 2; } else if ((val & 0xf0) && !(val & 0x08)) { val = 3; } else if ((val & 0xf8) && !(val & 0x04)) { val = 4; } else if ((val & 0xfc) && !(val & 0x02)) { val = 5; } else if ((val & 0xfe) && !(val & 0x01)) { val = 6; } else { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } val++; headerlen = 4 + val + (bs_from_end / 8) + (sr_from_end / 8); if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) { GST_LOG_OBJECT (flacdec, "invalid checksum"); return FALSE; } if (!last_sample_num) return TRUE; /* FIXME: This is can be 36 bit if variable block size is used, * fortunately not encoder supports this yet and we check for that * above. */ val = (guint32) g_utf8_get_char_validated ((gchar *) data + 4, -1); if (val == (guint32) - 1 || val == (guint32) - 2) { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } if (flacdec->min_blocksize == flacdec->max_blocksize) { *last_sample_num = (val + 1) * flacdec->min_blocksize; } else { *last_sample_num = 0; /* FIXME: + length of last block in samples */ } /* FIXME: only valid for fixed block size streams */ GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT, *last_sample_num); if (flacdec->info.rate > 0 && *last_sample_num != 0) { GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %" GST_TIME_FORMAT, *last_sample_num, GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->info.rate)); } return TRUE; }