PyObject * _pygi_marshal_to_py_unichar (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, GIArgument *arg) { PyObject *py_obj = NULL; /* Preserve the bidirectional mapping between 0 and "" */ if (arg->v_uint32 == 0) { py_obj = PYGLIB_PyUnicode_FromString (""); } else if (g_unichar_validate (arg->v_uint32)) { gchar utf8[6]; gint bytes; bytes = g_unichar_to_utf8 (arg->v_uint32, utf8); py_obj = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes); } else { /* TODO: Convert the error to an exception. */ PyErr_Format (PyExc_TypeError, "Invalid unicode codepoint %" G_GUINT32_FORMAT, arg->v_uint32); } return py_obj; }
void strip_unicode(gchar * data, gsize len) { gsize i = 0; if (data != NULL) { for (i = 0; i < len; i++) { if (!g_unichar_validate(data[i])) { data[i] = ' '; } } } }
static gboolean param_unichar_validate (GParamSpec *pspec, GValue *value) { gunichar oval = value->data[0].v_uint; gboolean changed = FALSE; if (!g_unichar_validate (oval)) { value->data[0].v_uint = 0; changed = TRUE; } return changed; }
IBusText * ibus_text_new_from_unichar (gunichar c) { IBusText *text; gint len; if (!g_unichar_validate (c)) { return NULL; } text= g_object_new (IBUS_TYPE_TEXT, NULL); text->is_static = FALSE; text->text = (gchar *)g_malloc (12); len = g_unichar_to_utf8 (c, text->text); text->text[len] = 0; return text; }
/* Converts \uxxxx or \Uxxxxyyyy escapes into their UTF-8 equivalents. * Returns a newly allocated string. The input string must be valid utf-8. */ char *str_unescape_unicode(const char *utf8_string) { if(utf8_string == NULL) return NULL; dstring_t *unescaped = dstring_new(NULL); const char *p = utf8_string; while(p && *p) { gunichar uc = g_utf8_get_char(p); p = g_utf8_next_char(p); if(uc == '\\') { if(*p == 'u' && is_hex_string(p+1, 4)) { p++; uc = htons(get_ucs4_16(p)); p += 4; } else if(*p == 'U' && is_hex_string(p+1, 8)) { p++; uc = htonl(get_ucs4_32(p)); p += 8; } if(!g_unichar_validate(uc)) { continue; } } char utf8_buf[6]; int utf8_len = g_unichar_to_utf8(uc, utf8_buf); dstring_append_len(unescaped, utf8_buf, utf8_len); } char *result = unescaped->string; dstring_free(unescaped, 0); return result; }
static gunichar json_scanner_get_unichar (JsonScanner *scanner, guint *line_p, guint *position_p) { gunichar uchar; gchar ch; gint i; uchar = 0; for (i = 0; i < 4; i++) { ch = json_scanner_get_char (scanner, line_p, position_p); if (is_hex_digit (ch)) uchar += ((gunichar) to_hex_digit (ch) << ((3 - i) * 4)); else break; } g_assert (g_unichar_validate (uchar) || g_unichar_type (uchar) == G_UNICODE_SURROGATE); return uchar; }
void *validate_value(gint value_id, gint input_type, void *value) { // Local variables guint base_type; guint capabilities; gboolean capability_check; gchar *conversion_buffer = NULL; // Used when converting between unicode character types gchar *decimal_point; GString *error_string; gchar input_char; gunichar input_char_unicode; gchar *input_ptr; struct lconv *locale_info; gboolean match_found; gint output_gint; gint *output_gint_ptr; gfloat output_gfloat; gfloat *output_gfloat_ptr; GString *output_gstring; guint output_guint; guint *output_guint_ptr; guint string_counter; gint string_length; gint string_max; guint string_min; gfloat value_max; gfloat value_min; // Initialise various things base_type = get_valid_fields_base_type(value_id); capabilities = get_valid_fields_capabilities(value_id); input_ptr = (gchar *) value; output_gstring = g_string_new(NULL); locale_info = localeconv(); decimal_point = locale_info->decimal_point; switch (base_type) { case V_CHAR: // * We're validating a char or string * // We can only validate string input for this type of value if (V_CHAR != input_type) { return NULL; } // Get the length of the input string string_max = get_valid_fields_max_value(value_id); string_min = get_valid_fields_min_value(value_id); string_length = g_utf8_strlen(input_ptr, -1); // If the length of the string isn't in the acceptable range, return NULL if (string_length < string_min) return NULL; if ((string_length > string_max) && (-1 != string_max)) // -1 for string_max means "no maximum limit" return NULL; if (0 == string_length) { // 0 length string, so we just return it return output_gstring; } // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { // Get the next character input_char_unicode = g_utf8_get_char_validated(input_ptr, -1); if ((gunichar)-1 == input_char_unicode) { // The returned character was not a valid unicode character, so we indicate failure return NULL; } if ((gunichar)-2 == input_char_unicode) { // The returned character was not a valid unicode character, so we indicate failure return NULL; } // Convert the character to UTF-8 so we can process it conversion_buffer = g_ucs4_to_utf8(&input_char_unicode, 1, NULL, NULL, NULL); // Determine which character we're examining if (TRUE == g_unichar_isalnum(input_char_unicode)) { // It's a standard unicode alphanumeric character, so we accept it as is g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); } else { // * The input wasn't a standard alphanumic character, so check if it * // * is one of the characters in the capabilities list for this field * match_found = FALSE; capability_check = V_ANY_UNICHAR & capabilities; if (FALSE != capability_check) { // This field is allowed to have any valid unicode character if (TRUE == g_unichar_validate(input_char_unicode)) { // Yes, this is a valid unicode character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_SPACES & capabilities; if (FALSE != capability_check) { // This field is allowed to have spaces if (0 == g_strcmp0(" ", conversion_buffer)) { // Yes, this is a space character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_FULL_STOP & capabilities; if (FALSE != capability_check) { // This field is allowed to have full stops if (0 == g_strcmp0(".", conversion_buffer)) { // Yes, this is a full stop character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_HYPENS & capabilities; if (FALSE != capability_check) { // This field is allowed to have hypens if (0 == g_strcmp0("-", conversion_buffer)) { // Yes, this is a hypen character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_UNDERSCORES & capabilities; if (FALSE != capability_check) { // This field is allowed to have underscores if (0 == g_strcmp0("_", conversion_buffer)) { // Yes, this is an underscore character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_PATH_SEP & capabilities; if (FALSE != capability_check) { // This field is allowed to have path separator characters ('/', '\') if ((0 == g_strcmp0("/", conversion_buffer)) || (0 == g_strcmp0("\\", conversion_buffer))) { // Yes, this is a path separator character match_found = TRUE; output_gstring = g_string_append_c(output_gstring, G_DIR_SEPARATOR); // Output the OS correct version input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_EQUALS & capabilities; if (FALSE != capability_check) { // This field is allowed to have equals signs if (0 == g_strcmp0("=", conversion_buffer)) { // Yes, this is an equals sign character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_FORWARD_SLASHES & capabilities; if (FALSE != capability_check) { // This field is allowed to have forward slashes if (0 == g_strcmp0("/", conversion_buffer)) { // Yes, this is a forward slash character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_NEW_LINES & capabilities; if (FALSE != capability_check) { // This field is allowed to have new line characters if (0 == g_strcmp0("\n", conversion_buffer)) { // Yes, this is a new line character match_found = TRUE; output_gstring = g_string_append_c(output_gstring, '\n'); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_PLUSES & capabilities; if (FALSE != capability_check) { // This field is allowed to have pluses if (0 == g_strcmp0("+", conversion_buffer)) { // Yes, this is a plus character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_PERCENT & capabilities; if (FALSE != capability_check) { // This field is allowed to have the percent sign if (0 == g_strcmp0("%", conversion_buffer)) { // Yes, this is a percent sign match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_COLON & capabilities; if (FALSE != capability_check) { // This field is allowed to have colons if (0 == g_strcmp0(":", conversion_buffer)) { // Yes, this is a colon character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_AT & capabilities; if (FALSE != capability_check) { // This field is allowed to have the at symbol if (0 == g_strcmp0("@", conversion_buffer)) { // Yes, this is an at character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_QUESTION & capabilities; if (FALSE != capability_check) { // This field is allowed to have the question mark if (0 == g_strcmp0("?", conversion_buffer)) { // Yes, this is a question mark character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } capability_check = V_AMPERSAND & capabilities; if (FALSE != capability_check) { // This field is allowed to have the ampersand character if (0 == g_strcmp0("&", conversion_buffer)) { // Yes, this is an ampersand character match_found = TRUE; g_string_append_printf(output_gstring, "%s", conversion_buffer); input_ptr = g_utf8_find_next_char(input_ptr, NULL); continue; } } // The character we are checking is not in the list of valid inputs for this field if (FALSE == match_found) { g_free(conversion_buffer); g_string_free(output_gstring, TRUE); return NULL; } } } // Remove any leading and/or trailing white space output_gstring->str = g_strstrip(output_gstring->str); output_gstring->len = strlen(output_gstring->str); // Recheck the length of the output string if (output_gstring->len < string_min) { g_free(conversion_buffer); g_string_free(output_gstring, TRUE); return NULL; } // Free the memory used so far if (0 != string_length) { g_free(conversion_buffer); } // The string seems to be valid, so return it for use return output_gstring; break; case V_FLOAT_UNSIGNED: // * We're validating an unsigned float * // If we're working with string input, we need to convert it to a float first if (V_CHAR == input_type) { // * We're working with string input * // Get the length of the input string string_length = strlen((gchar *) value); // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { input_char = ((gchar *) value)[string_counter]; // Check for decimal digits if (TRUE == g_ascii_isdigit(input_char)) { output_gstring = g_string_append_c(output_gstring, input_char); } else { // This field is allowed to have full stops. Is this character a full stop? if (0 == g_ascii_strncasecmp(".", &input_char, 1)) { // Yes, this is a full stop character output_gstring = g_string_append_c(output_gstring, *decimal_point); match_found = TRUE; continue; } // This field is allowed to have commas (equiv to full stop in some locales). Is this character a comma? if (0 == g_ascii_strncasecmp(",", &input_char, 1)) { // Yes, this is a comma character output_gstring = g_string_append_c(output_gstring, *decimal_point); match_found = TRUE; continue; } // The character we are checking is not in the list of valid inputs for this field if (FALSE == match_found) { g_string_free(output_gstring, TRUE); return NULL; } } } // Convert the string to a float output_gfloat = (gfloat) g_strtod(output_gstring->str, NULL); } else { // We're working with a float input, so just copy the value directly output_gfloat = *((gfloat *) value); } // Is the float value within the defined bounds? value_max = get_valid_fields_max_value(value_id); value_min = get_valid_fields_min_value(value_id); if ((output_gfloat < value_min) || (output_gfloat > value_max)) { // Value is out of bounds, so fail g_string_free(output_gstring, TRUE); return NULL; } // The value looks ok, so we copy it to newly allocated memory, to pass it back output_gfloat_ptr = g_try_new0(gfloat, 1); if (NULL == output_gfloat_ptr) { // Unable to allocate memory for the new value, so fail g_string_free(output_gstring, TRUE); return NULL; } *output_gfloat_ptr = output_gfloat; // Free the string memory allocated in this function g_string_free(output_gstring, TRUE); return output_gfloat_ptr; case V_INT_UNSIGNED: // * We're validating an unsigned integer * // If we're working with string input, we need to convert it to an integer first if (V_CHAR == input_type) { // * We're working with string input * // Get the length of the input string string_length = strlen((gchar *) value); // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { input_char = ((gchar *) value)[string_counter]; // Check for decimal digits if (TRUE == g_ascii_isdigit(input_char)) { output_gstring = g_string_append_c(output_gstring, input_char); } else { // This wasn't a valid character g_string_free(output_gstring, TRUE); return NULL; } } // Convert the string to an integer output_guint = atoi(output_gstring->str); } else { // We're working with integer input, so just copy the value directly output_guint = *((guint *) value); } // Is the integer value within the defined bounds? value_max = get_valid_fields_max_value(value_id); value_min = get_valid_fields_min_value(value_id); if ((output_guint < value_min) || (output_guint > value_max)) { // Value is out of bounds, so fail g_string_free(output_gstring, TRUE); return NULL; } // The value looks ok, so we copy it to newly allocated memory, to pass it back output_guint_ptr = g_try_new0(guint, 1); if (NULL == output_guint_ptr) { // Unable to allocate memory for the new value, so fail g_string_free(output_gstring, TRUE); return NULL; } *output_guint_ptr = output_guint; // Free the string memory allocated in this function g_string_free(output_gstring, TRUE); return output_guint_ptr; case V_INT_SIGNED: // * We're validating a signed integer * // If we're working with string input, we need to convert it to an integer first if (V_CHAR == input_type) { // * We're working with string input * // Get the length of the input string string_length = strlen((gchar *) value); // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { input_char = ((gchar *) value)[string_counter]; // Check for decimal digits if (TRUE == g_ascii_isdigit(input_char)) { output_gstring = g_string_append_c(output_gstring, input_char); } else { // * The input wasn't a standard digit character, so check if it * // * is one of the characters in the capabilities list for this field * match_found = FALSE; capability_check = V_HYPENS & capabilities; if (FALSE != capability_check) { // This field is allowed to have hypens if (0 == g_ascii_strncasecmp("-", &input_char, 1)) { // Yes, this is a hypen character match_found = TRUE; g_string_append_printf(output_gstring, "%s", "-"); } } // The character we are checking is not in the list of valid inputs for this field if (FALSE == match_found) { g_string_free(output_gstring, TRUE); return NULL; } } } // Convert the string to an integer output_gint = atoi(output_gstring->str); } else { // We're working with integer input, so just copy the value directly output_gint = *((gint *) value); } // Is the integer value within the defined bounds? value_max = get_valid_fields_max_value(value_id); value_min = get_valid_fields_min_value(value_id); if ((output_gint < value_min) || (output_gint > value_max)) { // Value is out of bounds, so fail g_string_free(output_gstring, TRUE); return NULL; } // The value looks ok, so we copy it to newly allocated memory, to pass it back output_gint_ptr = g_try_new0(gint, 1); if (NULL == output_gint_ptr) { // Unable to allocate memory for the new value, so fail g_string_free(output_gstring, TRUE); return NULL; } *output_gint_ptr = output_gint; // Free the string memory allocated in this function g_string_free(output_gstring, TRUE); return output_gint_ptr; case V_RESOLUTION: // * We're working with a resolution (text string) input. i.e. '1920x1200 pixels' * // Get the length of the input string string_length = strlen((gchar *) value); string_max = get_valid_fields_max_value(value_id); string_min = get_valid_fields_min_value(value_id); // If the length of the string isn't in the acceptable range, return NULL if ((string_length < string_min) || (string_length > string_max)) return NULL; // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { input_char = ((gchar *) value)[string_counter]; // Check for decimal digits if (TRUE == g_ascii_isdigit(input_char)) { output_gstring = g_string_append_c(output_gstring, input_char); } else { match_found = FALSE; // This field is allowed to have the ' ' and 'x' characters . Is this character one of those? if (0 == g_ascii_strncasecmp(" ", &input_char, 1)) { // Yes, this is a space character, so we've already collected the required resolution // info and we can just return the resolution part of the string so far // Remove any leading and/or trailing white space output_gstring->str = g_strstrip(output_gstring->str); output_gstring->len = strlen(output_gstring->str); // Recheck the length of the output string if ((string_length < string_min) || (string_length > string_max)) return NULL; // The string seems to be valid, so return it for use return output_gstring; } if (0 == g_ascii_strncasecmp("x", &input_char, 1)) { // Yes, this is a 'x' character output_gstring = g_string_append_c(output_gstring, 'x'); match_found = TRUE; continue; } if (FALSE == match_found) { // This wasn't a valid character g_string_free(output_gstring, TRUE); return NULL; } } } // Remove any leading and/or trailing white space output_gstring->str = g_strstrip(output_gstring->str); output_gstring->len = strlen(output_gstring->str); // Recheck the length of the output string if ((string_length < string_min) || (string_length > string_max)) return NULL; // The string seems to be valid, so return it for use return output_gstring; case V_ZOOM: // * We're working with a zoom level. i.e. "100%" or "Fit to width" * // Get the length of the input string string_length = g_utf8_strlen((gchar *) value, -1); string_max = get_valid_fields_max_value(value_id); string_min = get_valid_fields_min_value(value_id); // If the length of the string isn't in the acceptable range, return NULL if ((string_length < string_min) || (string_length > string_max)) return NULL; // If the string is "Fit to width" or a localised version of it if ((0 == g_strcmp0("Fit to width", (gchar *) value)) || (0 == g_strcmp0(_("Fit to width"), (gchar *) value))) { // Yes, this is the "Fit to width" value output_gstring = g_string_assign(output_gstring, value); return output_gstring; } // * The incoming string isn't the "Fit to width" value, * // * so should only consist of decimal characters and '%' * // Sanitise each character of the input string for (string_counter = 0; string_counter < string_length; string_counter++) { input_char = ((gchar *) value)[string_counter]; // Check for decimal digits if (TRUE == g_ascii_isdigit(input_char)) { output_gstring = g_string_append_c(output_gstring, input_char); continue; } // Check for '%' character if (0 == g_ascii_strncasecmp("%", &input_char, 1)) { // Yes, this is a '%' character output_gstring = g_string_append_c(output_gstring, '%'); continue; } // This wasn't a valid character g_string_free(output_gstring, TRUE); return NULL; } return output_gstring; default: // Unknown value type, we should never get here error_string = g_string_new(NULL); g_string_printf(error_string, "%s ED119: %s - '%s'", _("Error"), _("Unknown value passed to validation function"), get_valid_fields_name(value_id)); display_warning(error_string->str); g_string_free(error_string, TRUE); return NULL; } // If we get here, then something went wrong! return NULL; }
/* Wrapper, in case we want to support a newer unicode version than glib */ gboolean mcharmap_unichar_validate(gunichar ch) { return g_unichar_validate(ch); }
GSList * parseTestFile (gchar * filename) { /* open test file */ GIOChannel *testFile = g_io_channel_new_file (filename, "r", NULL); if (testFile == NULL) return NULL; GSList *testPairs = NULL; GString *line = g_string_new(NULL); int linecount = 0; while (g_io_channel_read_line_string (testFile, line, NULL, NULL) == G_IO_STATUS_NORMAL) { linecount++; /* strip of comments and whitespace */ for (int i = 0; i < line->len; i++) { if (line->str[i] == '#') { g_string_truncate (line, i); break; } } g_strstrip (line->str); /* skip line if blank */ if (strlen (line->str) == 0) continue; /* initialize test pair */ TestPair *testPair = g_malloc (sizeof (TestPair)); testPair->linenr = linecount; testPair->line = g_strdup (line->str); testPair->keyevent = NULL; testPair->commands = NULL; TIL_Keyevent *keyevent = NULL; /*gboolean hit = FALSE;*/ TIL_Keyevent_Type type; gboolean autorep = FALSE; gint modifiers = 0; /* extract the fields */ gchar **fields = g_strsplit (line->str, "::", 0); if (fields[0] == NULL || fields[1] == NULL) goto parseError; /* * FIELD 1 - EVENT TYPE */ g_strstrip (fields[0]); if (g_ascii_strcasecmp (fields[0], "press") == 0) { type = TIL_Event_Pressed; } else if (g_ascii_strcasecmp (fields[0], "pressrep") == 0) { type = TIL_Event_Pressed; autorep = TRUE; } else if (g_ascii_strcasecmp (fields[0], "release") == 0) { type = TIL_Event_Released; } /*else if (g_ascii_strcasecmp (fields[0], "hit") == 0) { type = TIL_Event_Pressed; hit = TRUE; }*/ else { goto parseError; } /* * FIELD 2 - KEY */ char *keystring = g_strstrip (fields[1]); TIL_Keycode code = TIL_Key_unknown; GString *text = g_string_new (""); gboolean hasNonPrintable = FALSE; /* TRUE <=> the key sequence has non-printable chars */ while (*keystring != '\0') { gunichar c = g_utf8_get_char_validated (keystring, -1); if (!g_unichar_validate (c)) goto parseError; keystring = g_utf8_next_char (keystring); if (c == (gunichar) '<' && *keystring != '\0') { /* an escaped key */ gchar *esckey = keystring; /* go to the next '>' */ gunichar ch; do { ch = g_utf8_get_char_validated (keystring, -1); if (!g_unichar_validate (ch)) goto parseError; keystring = g_utf8_next_char (keystring); } while (*keystring != '\0' && ch != (gunichar) '>'); if (*keystring == '\0' && ch != (gunichar) '>') { /* string not finished with '>' */ goto parseError; } /* overwrite the '>' with NULL character, so that esckey contains the string * inside the brackets */ *(keystring - 1) = '\0'; TIL_Keycode tempcode = unescapeKey (esckey); if (tempcode == TIL_Key_unknown) goto parseError; c = keyToChar (tempcode); if (c == 0) { /* non-printable character */ if (code != TIL_Key_unknown) /* we already have a key - this is not valid */ goto parseError; hasNonPrintable = TRUE; code = tempcode; } } if (c != 0) { if (hasNonPrintable) /* non-printable characters and text together is not valid */ goto parseError; g_string_append_unichar (text, c); } } /* * FIELD 3 - MODIFIERS */ gchar **modv = g_strsplit (fields[2], ",", 0); gint i = 0; while (modv[i] != NULL) { g_strstrip (modv[i]); switch (g_ascii_toupper (modv[i][0])) { case 'S': modifiers |= TIL_Mod_Shift; break; case 'C': modifiers |= TIL_Mod_Control; break; case 'A': modifiers |= TIL_Mod_Alt; break; case 'M': modifiers |= TIL_Mod_Meta; break; default: break; } i++; } g_strfreev (modv); /* * CONSTRUCT THE KEY EVENTS */ keyevent = g_malloc (sizeof (TIL_Keyevent) + text->len + 1); keyevent->type = type; keyevent->autorep = autorep; keyevent->modifiers = modifiers; keyevent->keycode = code; strcpy (keyevent->text, text->str); /* * REMAINING FIELDS: COMMANDS */ GSList *cmds = NULL; int numCmds = 0; if (fields[3] != NULL) { /* ignore the last field if it consists only of white space */ g_strstrip (fields[3]); if (*fields[3] != '\0') { for (int i = 3; fields[i] != NULL; i++) { TIL_Cmd *cmd = cmdFromString (fields[i]); if (cmd == NULL) { GSList *work = cmds; while (work != NULL) { g_free(work->data); work = g_slist_next (work); } goto parseError; } cmds = g_slist_append (cmds, cmd); numCmds++; } } } /* * BUILD THE TEST PAIR */ testPair->keyevent = keyevent; testPair->commands = g_malloc (sizeof (TIL_Cmd *) * (numCmds + 1)); GSList *work = cmds; for (int j = 0; j < numCmds; j++) { testPair->commands[j] = work->data; work = g_slist_next (work); } testPair->commands[numCmds] = NULL; g_strfreev (fields); g_slist_free (cmds); testPairs = g_slist_append (testPairs, testPair); continue; parseError: g_free (keyevent); testPairs = g_slist_append (testPairs, testPair); } /* end while */ /* cleanup */ g_io_channel_shutdown (testFile, FALSE, NULL); g_io_channel_unref (testFile); g_string_free (line, FALSE); return testPairs; }
static void json_scanner_get_token_ll (JsonScanner *scanner, GTokenType *token_p, GTokenValue *value_p, guint *line_p, guint *position_p) { JsonScannerConfig *config; GTokenType token; gboolean in_comment_multi; gboolean in_comment_single; gboolean in_string_sq; gboolean in_string_dq; GString *gstring; GTokenValue value; guchar ch; config = scanner->config; (*value_p).v_int64 = 0; if ((scanner->text >= scanner->text_end && scanner->input_fd < 0) || scanner->token == G_TOKEN_EOF) { *token_p = G_TOKEN_EOF; return; } in_comment_multi = FALSE; in_comment_single = FALSE; in_string_sq = FALSE; in_string_dq = FALSE; gstring = NULL; do /* while (ch != 0) */ { gboolean dotted_float = FALSE; ch = json_scanner_get_char (scanner, line_p, position_p); value.v_int64 = 0; token = G_TOKEN_NONE; /* this is *evil*, but needed ;( * we first check for identifier first character, because it * might interfere with other key chars like slashes or numbers */ if (config->scan_identifier && ch && strchr (config->cset_identifier_first, ch)) goto identifier_precedence; switch (ch) { case 0: token = G_TOKEN_EOF; (*position_p)++; /* ch = 0; */ break; case '/': if (!config->scan_comment_multi || json_scanner_peek_next_char (scanner) != '*') goto default_case; json_scanner_get_char (scanner, line_p, position_p); token = G_TOKEN_COMMENT_MULTI; in_comment_multi = TRUE; gstring = g_string_new (NULL); while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0) { if (ch == '*' && json_scanner_peek_next_char (scanner) == '/') { json_scanner_get_char (scanner, line_p, position_p); in_comment_multi = FALSE; break; } else gstring = g_string_append_c (gstring, ch); } ch = 0; break; case '\'': if (!config->scan_string_sq) goto default_case; token = G_TOKEN_STRING; in_string_sq = TRUE; gstring = g_string_new (NULL); while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0) { if (ch == '\'') { in_string_sq = FALSE; break; } else gstring = g_string_append_c (gstring, ch); } ch = 0; break; case '"': if (!config->scan_string_dq) goto default_case; token = G_TOKEN_STRING; in_string_dq = TRUE; gstring = g_string_new (NULL); while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0) { if (ch == '"') { in_string_dq = FALSE; break; } else { if (ch == '\\') { ch = json_scanner_get_char (scanner, line_p, position_p); switch (ch) { guint i; guint fchar; case 0: break; case '\\': gstring = g_string_append_c (gstring, '\\'); break; case 'n': gstring = g_string_append_c (gstring, '\n'); break; case 't': gstring = g_string_append_c (gstring, '\t'); break; case 'r': gstring = g_string_append_c (gstring, '\r'); break; case 'b': gstring = g_string_append_c (gstring, '\b'); break; case 'f': gstring = g_string_append_c (gstring, '\f'); break; case 'u': fchar = json_scanner_peek_next_char (scanner); if (is_hex_digit (fchar)) { gunichar ucs; ucs = json_scanner_get_unichar (scanner, line_p, position_p); if (g_unichar_type (ucs) == G_UNICODE_SURROGATE) { /* read next surrogate */ if ('\\' == json_scanner_get_char (scanner, line_p, position_p) && 'u' == json_scanner_get_char (scanner, line_p, position_p)) { gunichar ucs_lo = json_scanner_get_unichar (scanner, line_p, position_p); g_assert (g_unichar_type (ucs_lo) == G_UNICODE_SURROGATE); ucs = (((ucs & 0x3ff) << 10) | (ucs_lo & 0x3ff)) + 0x10000; } } g_assert (g_unichar_validate (ucs)); gstring = g_string_append_unichar (gstring, ucs); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': i = ch - '0'; fchar = json_scanner_peek_next_char (scanner); if (fchar >= '0' && fchar <= '7') { ch = json_scanner_get_char (scanner, line_p, position_p); i = i * 8 + ch - '0'; fchar = json_scanner_peek_next_char (scanner); if (fchar >= '0' && fchar <= '7') { ch = json_scanner_get_char (scanner, line_p, position_p); i = i * 8 + ch - '0'; } } gstring = g_string_append_c (gstring, i); break; default: gstring = g_string_append_c (gstring, ch); break; } } else gstring = g_string_append_c (gstring, ch); } } ch = 0; break; case '.': if (!config->scan_float) goto default_case; token = G_TOKEN_FLOAT; dotted_float = TRUE; ch = json_scanner_get_char (scanner, line_p, position_p); goto number_parsing; case '$': if (!config->scan_hex_dollar) goto default_case; token = G_TOKEN_HEX; ch = json_scanner_get_char (scanner, line_p, position_p); goto number_parsing; case '0': if (config->scan_octal) token = G_TOKEN_OCTAL; else token = G_TOKEN_INT; ch = json_scanner_peek_next_char (scanner); if (config->scan_hex && (ch == 'x' || ch == 'X')) { token = G_TOKEN_HEX; json_scanner_get_char (scanner, line_p, position_p); ch = json_scanner_get_char (scanner, line_p, position_p); if (ch == 0) { token = G_TOKEN_ERROR; value.v_error = G_ERR_UNEXP_EOF; (*position_p)++; break; } if (json_scanner_char_2_num (ch, 16) < 0) { token = G_TOKEN_ERROR; value.v_error = G_ERR_DIGIT_RADIX; ch = 0; break; } } else if (config->scan_binary && (ch == 'b' || ch == 'B')) { token = G_TOKEN_BINARY; json_scanner_get_char (scanner, line_p, position_p); ch = json_scanner_get_char (scanner, line_p, position_p); if (ch == 0) { token = G_TOKEN_ERROR; value.v_error = G_ERR_UNEXP_EOF; (*position_p)++; break; } if (json_scanner_char_2_num (ch, 10) < 0) { token = G_TOKEN_ERROR; value.v_error = G_ERR_NON_DIGIT_IN_CONST; ch = 0; break; } } else ch = '0'; /* fall through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': number_parsing: { gboolean in_number = TRUE; gchar *endptr; if (token == G_TOKEN_NONE) token = G_TOKEN_INT; gstring = g_string_new (dotted_float ? "0." : ""); gstring = g_string_append_c (gstring, ch); do /* while (in_number) */ { gboolean is_E; is_E = token == G_TOKEN_FLOAT && (ch == 'e' || ch == 'E'); ch = json_scanner_peek_next_char (scanner); if (json_scanner_char_2_num (ch, 36) >= 0 || (config->scan_float && ch == '.') || (is_E && (ch == '+' || ch == '-'))) { ch = json_scanner_get_char (scanner, line_p, position_p); switch (ch) { case '.': if (token != G_TOKEN_INT && token != G_TOKEN_OCTAL) { value.v_error = token == G_TOKEN_FLOAT ? G_ERR_FLOAT_MALFORMED : G_ERR_FLOAT_RADIX; token = G_TOKEN_ERROR; in_number = FALSE; } else { token = G_TOKEN_FLOAT; gstring = g_string_append_c (gstring, ch); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': gstring = g_string_append_c (gstring, ch); break; case '-': case '+': if (token != G_TOKEN_FLOAT) { token = G_TOKEN_ERROR; value.v_error = G_ERR_NON_DIGIT_IN_CONST; in_number = FALSE; } else gstring = g_string_append_c (gstring, ch); break; case 'e': case 'E': if ((token != G_TOKEN_HEX && !config->scan_float) || (token != G_TOKEN_HEX && token != G_TOKEN_OCTAL && token != G_TOKEN_FLOAT && token != G_TOKEN_INT)) { token = G_TOKEN_ERROR; value.v_error = G_ERR_NON_DIGIT_IN_CONST; in_number = FALSE; } else { if (token != G_TOKEN_HEX) token = G_TOKEN_FLOAT; gstring = g_string_append_c (gstring, ch); } break; default: if (token != G_TOKEN_HEX) { token = G_TOKEN_ERROR; value.v_error = G_ERR_NON_DIGIT_IN_CONST; in_number = FALSE; } else gstring = g_string_append_c (gstring, ch); break; } } else in_number = FALSE; } while (in_number); endptr = NULL; if (token == G_TOKEN_FLOAT) value.v_float = g_strtod (gstring->str, &endptr); else { guint64 ui64 = 0; switch (token) { case G_TOKEN_BINARY: ui64 = g_ascii_strtoull (gstring->str, &endptr, 2); break; case G_TOKEN_OCTAL: ui64 = g_ascii_strtoull (gstring->str, &endptr, 8); break; case G_TOKEN_INT: ui64 = g_ascii_strtoull (gstring->str, &endptr, 10); break; case G_TOKEN_HEX: ui64 = g_ascii_strtoull (gstring->str, &endptr, 16); break; default: ; } if (scanner->config->store_int64) value.v_int64 = ui64; else value.v_int = ui64; } if (endptr && *endptr) { token = G_TOKEN_ERROR; if (*endptr == 'e' || *endptr == 'E') value.v_error = G_ERR_NON_DIGIT_IN_CONST; else value.v_error = G_ERR_DIGIT_RADIX; } g_string_free (gstring, TRUE); gstring = NULL; ch = 0; } /* number_parsing:... */ break; default: default_case: { if (config->cpair_comment_single && ch == config->cpair_comment_single[0]) { token = G_TOKEN_COMMENT_SINGLE; in_comment_single = TRUE; gstring = g_string_new (NULL); ch = json_scanner_get_char (scanner, line_p, position_p); while (ch != 0) { if (ch == config->cpair_comment_single[1]) { in_comment_single = FALSE; ch = 0; break; } gstring = g_string_append_c (gstring, ch); ch = json_scanner_get_char (scanner, line_p, position_p); } /* ignore a missing newline at EOF for single line comments */ if (in_comment_single && config->cpair_comment_single[1] == '\n') in_comment_single = FALSE; } else if (config->scan_identifier && ch && strchr (config->cset_identifier_first, ch)) { identifier_precedence: if (config->cset_identifier_nth && ch && strchr (config->cset_identifier_nth, json_scanner_peek_next_char (scanner))) { token = G_TOKEN_IDENTIFIER; gstring = g_string_new (NULL); gstring = g_string_append_c (gstring, ch); do { ch = json_scanner_get_char (scanner, line_p, position_p); gstring = g_string_append_c (gstring, ch); ch = json_scanner_peek_next_char (scanner); } while (ch && strchr (config->cset_identifier_nth, ch)); ch = 0; } else if (config->scan_identifier_1char) { token = G_TOKEN_IDENTIFIER; value.v_identifier = g_new0 (gchar, 2); value.v_identifier[0] = ch; ch = 0; } } if (ch) { if (config->char_2_token) token = ch; else { token = G_TOKEN_CHAR; value.v_char = ch; } ch = 0; } } /* default_case:... */ break; } g_assert (ch == 0 && token != G_TOKEN_NONE); /* paranoid */ } while (ch != 0); if (in_comment_multi || in_comment_single || in_string_sq || in_string_dq) { token = G_TOKEN_ERROR; if (gstring) { g_string_free (gstring, TRUE); gstring = NULL; } (*position_p)++; if (in_comment_multi || in_comment_single) value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT; else /* (in_string_sq || in_string_dq) */ value.v_error = G_ERR_UNEXP_EOF_IN_STRING; } if (gstring) { value.v_string = g_string_free (gstring, FALSE); gstring = NULL; } if (token == G_TOKEN_IDENTIFIER) { if (config->scan_symbols) { JsonScannerKey *key; guint scope_id; scope_id = scanner->scope_id; key = json_scanner_lookup_internal (scanner, scope_id, value.v_identifier); if (!key && scope_id && scanner->config->scope_0_fallback) key = json_scanner_lookup_internal (scanner, 0, value.v_identifier); if (key) { g_free (value.v_identifier); token = G_TOKEN_SYMBOL; value.v_symbol = key->value; } } if (token == G_TOKEN_IDENTIFIER && config->scan_identifier_NULL && strlen (value.v_identifier) == 4) { gchar *null_upper = "NULL"; gchar *null_lower = "null"; if (scanner->config->case_sensitive) { if (value.v_identifier[0] == null_upper[0] && value.v_identifier[1] == null_upper[1] && value.v_identifier[2] == null_upper[2] && value.v_identifier[3] == null_upper[3]) token = G_TOKEN_IDENTIFIER_NULL; } else { if ((value.v_identifier[0] == null_upper[0] || value.v_identifier[0] == null_lower[0]) && (value.v_identifier[1] == null_upper[1] || value.v_identifier[1] == null_lower[1]) && (value.v_identifier[2] == null_upper[2] || value.v_identifier[2] == null_lower[2]) && (value.v_identifier[3] == null_upper[3] || value.v_identifier[3] == null_lower[3])) token = G_TOKEN_IDENTIFIER_NULL; } } } *token_p = token; *value_p = value; }
static void update_view(PussVConsole* self) { VConsole* vcon = self->vcon; SMALL_RECT* range; DWORD i, j, h, w, sz; DWORD cx, cy; gchar text[(MAX_SCR_LEN+1)*6 + MAX_SCR_ROW]; gchar* pd = text; CHAR_INFO* ps; GtkTextIter it, end; GtkTextView* txt_view = GTK_TEXT_VIEW(self->view); GtkTextBuffer* txt_buf = gtk_text_view_get_buffer(txt_view); if( !self->vcon || !self->need_update ) return; self->need_update = FALSE; range = &(vcon->screen_info->srWindow); h = range->Bottom - range->Top + 1; w = range->Right - range->Left + 1; cy = vcon->screen_info->dwCursorPosition.Y - range->Top; cx = vcon->screen_info->dwCursorPosition.X - range->Left; // scroll bar update self->adjust->lower = 1; self->adjust->upper = vcon->screen_info->dwSize.Y; self->adjust->step_increment = 1; self->adjust->page_size = h; self->adjust->page_increment = h; self->adjust->value = range->Top; // screen buffer update ps = vcon->screen_buffer; for( i=0; i<h; ++i ) { for( j=0; j<w; ++j ) { if( ps->Char.UnicodeChar && g_unichar_validate(ps->Char.UnicodeChar) ) { sz = g_unichar_to_utf8(ps->Char.UnicodeChar, pd); pd += sz; if( ps->Char.UnicodeChar > 0xff ) { ++j; if( cy==i ) --cx; } } else { //g_print("unknown = %d\n", ps->Char.UnicodeChar); } ++ps; } // remove end space while(*(pd-1)=='\t' || *(pd-1)==' ' ) --pd; *pd = '\n'; ++pd; } *pd = '\0'; sz = (DWORD)(pd - text); gtk_text_buffer_set_text(txt_buf, text, sz); // cursor update h = gtk_text_buffer_get_line_count(txt_buf); if( cy >= h ) { gtk_text_view_set_cursor_visible(txt_view, FALSE); } else { gtk_text_buffer_get_iter_at_line(txt_buf, &it, cy); end = it; if( gtk_text_iter_forward_chars(&end, cx) ) { it = end; } else { if( gtk_text_iter_forward_to_line_end(&end) ) { it = end; } else { gtk_text_buffer_get_iter_at_line(txt_buf, &it, cy); } } gtk_text_buffer_place_cursor(txt_buf, &it); gtk_text_view_set_cursor_visible(txt_view, TRUE); } gtk_adjustment_changed(self->adjust); }
GtkTextBuffer *gtk_text_buffer_duplicate(GtkTextBuffer *source_buffer) { // Local variables gchar *conversion_buffer; // Used when converting between unicode character types GtkTextIter end_iter; GtkTextIter end_iter_minus_one; gint end_offset; gint i; guint loop_counter; GtkTextIter loop_iter; GtkTextBuffer *new_text_buffer; guint num_tags; GtkTextIter source_buffer_end; GtkTextIter source_buffer_start; gint start_offset; GSList *tag_list; GtkTextTag *tag_ptr; gunichar temp_char; GString *temp_gstring; // Validate the tags in the source buffer text_layer_dialog_validate_buffer_tag_quantity(GTK_TEXT_BUFFER(source_buffer)); // Initialise various things temp_gstring = g_string_new(NULL); // Create a new text buffer new_text_buffer = gtk_text_buffer_new(get_text_tags_table()); // Get the bounds of the source buffer gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(source_buffer), &source_buffer_start, &source_buffer_end); gtk_text_iter_order(&source_buffer_start, &source_buffer_end); // Scan through the source text buffer one character at a time, getting the character and the tags that apply to it start_offset = gtk_text_iter_get_offset(&source_buffer_start); end_offset = gtk_text_iter_get_offset(&source_buffer_end); for (i = 0; i < end_offset; i++) { // Copy one character from the source text buffer to the new destination text buffer gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(source_buffer), &loop_iter, i); temp_char = gtk_text_iter_get_char(&loop_iter); conversion_buffer = g_ucs4_to_utf8(&temp_char, 1, NULL, NULL, NULL); if (NULL == conversion_buffer) { g_string_printf(temp_gstring, "%s ED441: %s", _("Error"), _("Could not convert unicode character from ucs4 to utf8.")); display_warning(temp_gstring->str); continue; } // Validate the retrieved character if (TRUE != g_unichar_validate(temp_char)) { // Something other than a unicode character was retrieved g_string_printf(temp_gstring, "%s ED442: %s", _("Error"), _("Invalid unicode character found in text.")); display_warning(temp_gstring->str); continue; } gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(new_text_buffer), conversion_buffer, -1); g_free(conversion_buffer); // Copy the tags from the character in the source buffer to the new character in the destination buffer tag_list = gtk_text_iter_get_tags(&loop_iter); num_tags = g_slist_length(tag_list); gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(new_text_buffer), &end_iter); end_iter_minus_one = end_iter; gtk_text_iter_backward_char(&end_iter_minus_one); for (loop_counter = 0; loop_counter < num_tags; loop_counter++) { // Copy each tag from the source text buffer to the destination one tag_ptr = g_slist_nth_data(tag_list, loop_counter); gtk_text_buffer_apply_tag(GTK_TEXT_BUFFER(new_text_buffer), tag_ptr, &end_iter_minus_one, &end_iter); } g_slist_free(tag_list); } g_string_free(temp_gstring, TRUE); // Validate the tags in the duplicated buffer text_layer_dialog_validate_buffer_tag_quantity(GTK_TEXT_BUFFER(new_text_buffer)); // Return the duplicated text buffer return new_text_buffer; }
static gboolean on_captured_event (ClutterText *text, ClutterEvent *event, gpointer dummy G_GNUC_UNUSED) { gboolean is_unicode_mode = FALSE; gunichar c; guint keyval; if (event->type != CLUTTER_KEY_PRESS) return FALSE; is_unicode_mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (text), "unicode-mode")); c = clutter_event_get_key_unicode (event); keyval = clutter_event_get_key_symbol (event); if (keyval == CLUTTER_KEY_U) { if (is_unicode_mode) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); clutter_text_set_preedit_string (text, NULL, NULL, 0); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (FALSE)); g_object_set_data (G_OBJECT (text), "unicode-str", NULL); g_string_free (str, TRUE); return FALSE; } if (clutter_event_has_control_modifier (event)) { PangoAttrList *attrs; PangoAttribute *a; GString *str = g_string_sized_new (5); g_string_append (str, "u"); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (TRUE)); g_object_set_data (G_OBJECT (text), "unicode-str", str); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } return FALSE; } else if (is_unicode_mode && is_hex_digit (c)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); PangoAttrList *attrs; PangoAttribute *a; gchar buf[8]; gsize len; len = g_unichar_to_utf8 (c, buf); buf[len] = '\0'; g_string_append (str, buf); g_print ("added '%s' to '%s' (len:%d)\n", buf, str->str, (int) str->len); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } else if (is_unicode_mode && (keyval == CLUTTER_KEY_BackSpace)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); PangoAttrList *attrs; PangoAttribute *a; g_string_truncate (str, str->len - 1); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } else if (is_unicode_mode && (keyval == CLUTTER_KEY_Return || keyval == CLUTTER_KEY_KP_Enter || keyval == CLUTTER_KEY_ISO_Enter || keyval == CLUTTER_KEY_KP_Space)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); const gchar *contents = clutter_text_get_text (text); gunichar uchar = 0; gchar ch; gint i; clutter_text_set_preedit_string (text, NULL, NULL, 0); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (FALSE)); g_object_set_data (G_OBJECT (text), "unicode-str", NULL); for (i = 0; i < str->len; i++) { ch = str->str[i]; if (is_hex_digit (ch)) uchar += ((gunichar) to_hex_digit (ch) << ((4 - i) * 4)); } g_assert (g_unichar_validate (uchar)); g_string_overwrite (str, 0, contents); g_string_insert_unichar (str, clutter_text_get_cursor_position (text), uchar); i = clutter_text_get_cursor_position (text); clutter_text_set_text (text, str->str); if (i >= 0) i += 1; else i = -1; clutter_text_set_cursor_position (text, i); clutter_text_set_selection_bound (text, i); g_string_free (str, TRUE); return TRUE; } else return FALSE; }
/** * e_text_to_html_full: * @input: a NUL-terminated input buffer * @flags: some combination of the E_TEXT_TO_HTML_* flags defined * in e-html-utils.h * @color: color for citation highlighting * * This takes a buffer of text as input and produces a buffer of * "equivalent" HTML, subject to certain transformation rules. * * The set of possible flags is: * * - E_TEXT_TO_HTML_PRE: wrap the output HTML in <PRE> and * </PRE> Should only be used if @input is the entire * buffer to be converted. If e_text_to_html is being called with * small pieces of data, you should wrap the entire result in * <PRE> yourself. * * - E_TEXT_TO_HTML_CONVERT_NL: convert "\n" to "<BR>n" on * output. (Should not be used with E_TEXT_TO_HTML_PRE, since * that would result in double-newlines.) * * - E_TEXT_TO_HTML_CONVERT_SPACES: convert a block of N spaces * into N-1 non-breaking spaces and one normal space. A space * at the start of the buffer is always converted to a * non-breaking space, regardless of the following character, * which probably means you don't want to use this flag on * pieces of data that aren't delimited by at least line breaks. * * If E_TEXT_TO_HTML_CONVERT_NL and E_TEXT_TO_HTML_CONVERT_SPACES * are both defined, then TABs will also be converted to spaces. * * - E_TEXT_TO_HTML_CONVERT_URLS: wrap <a href="..."> </a> * around strings that look like URLs. * * - E_TEXT_TO_HTML_CONVERT_ADDRESSES: wrap <a href="mailto:..."> * </a> around strings that look like mail addresses. * * - E_TEXT_TO_HTML_MARK_CITATION: wrap <font color="..."> * </font> around citations (lines beginning with "> ", etc). * * - E_TEXT_TO_HTML_ESCAPE_8BIT: flatten everything to US-ASCII * * - E_TEXT_TO_HTML_CITE: quote the text with "> " at the start of each * line. * * Returns: a newly-allocated string containing HTML **/ gchar * e_text_to_html_full (const gchar *input, guint flags, guint32 color) { const guchar *cur, *next, *linestart; gchar *buffer = NULL; gchar *out = NULL; gint buffer_size = 0, col; gboolean colored = FALSE, saw_citation = FALSE; /* Allocate a translation buffer. */ buffer_size = strlen (input) * 2 + 5; buffer = g_malloc (buffer_size); out = buffer; if (flags & E_TEXT_TO_HTML_PRE) out += sprintf (out, "<PRE>"); col = 0; for (cur = linestart = (const guchar *) input; cur && *cur; cur = next) { gunichar u; if (flags & E_TEXT_TO_HTML_MARK_CITATION && col == 0) { saw_citation = is_citation (cur, saw_citation); if (saw_citation) { if (!colored) { gchar font[25]; g_snprintf (font, 25, "<FONT COLOR=\"#%06x\">", color); out = check_size (&buffer, &buffer_size, out, 25); out += sprintf (out, "%s", font); colored = TRUE; } } else if (colored) { const gchar *no_font = "</FONT>"; out = check_size (&buffer, &buffer_size, out, 9); out += sprintf (out, "%s", no_font); colored = FALSE; } /* Display mbox-mangled ">From" as "From" */ if (*cur == '>' && !saw_citation) cur++; } else if (flags & E_TEXT_TO_HTML_CITE && col == 0) { out = check_size (&buffer, &buffer_size, out, 5); out += sprintf (out, "> "); } u = g_utf8_get_char ((gchar *) cur); if (g_unichar_isalpha (u) && (flags & E_TEXT_TO_HTML_CONVERT_URLS)) { gchar *tmpurl = NULL, *refurl = NULL, *dispurl = NULL; if (!g_ascii_strncasecmp ((gchar *)cur, "http://", 7) || !g_ascii_strncasecmp ((gchar *)cur, "https://", 8) || !g_ascii_strncasecmp ((gchar *)cur, "ftp://", 6) || !g_ascii_strncasecmp ((gchar *)cur, "nntp://", 7) || !g_ascii_strncasecmp ((gchar *)cur, "mailto:", 7) || !g_ascii_strncasecmp ((gchar *)cur, "news:", 5) || !g_ascii_strncasecmp ((gchar *)cur, "file:", 5) || !g_ascii_strncasecmp ((gchar *)cur, "callto:", 7) || !g_ascii_strncasecmp ((gchar *)cur, "h323:", 5) || !g_ascii_strncasecmp ((gchar *)cur, "sip:", 4) || !g_ascii_strncasecmp ((gchar *)cur, "webcal:", 7)) { tmpurl = url_extract (&cur, TRUE); if (tmpurl) { refurl = e_text_to_html (tmpurl, 0); dispurl = g_strdup (refurl); } } else if (!g_ascii_strncasecmp ((gchar *)cur, "www.", 4) && is_url_char (*(cur + 4))) { tmpurl = url_extract (&cur, FALSE); if (tmpurl) { dispurl = e_text_to_html (tmpurl, 0); refurl = g_strdup_printf ("http://%s", dispurl); } } if (tmpurl) { out = check_size (&buffer, &buffer_size, out, strlen (refurl) + strlen (dispurl) + 15); out += sprintf (out, "<a href=\"%s\">%s</a>", refurl, dispurl); col += strlen (tmpurl); g_free (tmpurl); g_free (refurl); g_free (dispurl); } if (!*cur) break; u = g_utf8_get_char ((gchar *) cur); } if (u == '@' && (flags & E_TEXT_TO_HTML_CONVERT_ADDRESSES)) { gchar *addr, *dispaddr, *outaddr; addr = email_address_extract (&cur, &out, linestart); if (addr) { dispaddr = e_text_to_html (addr, 0); outaddr = g_strdup_printf ("<a href=\"mailto:%s\">%s</a>", addr, dispaddr); out = check_size (&buffer, &buffer_size, out, strlen (outaddr)); out += sprintf (out, "%s", outaddr); col += strlen (addr); g_free (addr); g_free (dispaddr); g_free (outaddr); if (!*cur) break; u = g_utf8_get_char ((gchar *) cur); } } if (!g_unichar_validate (u)) { /* Sigh. Someone sent undeclared 8-bit data. * Assume it's iso-8859-1. */ u = *cur; next = cur + 1; } else next = (const guchar *) g_utf8_next_char (cur); out = check_size (&buffer, &buffer_size, out, 10); switch (u) { case '<': strcpy (out, "<"); out += 4; col++; break; case '>': strcpy (out, ">"); out += 4; col++; break; case '&': strcpy (out, "&"); out += 5; col++; break; case '"': strcpy (out, """); out += 6; col++; break; case '\n': if (flags & E_TEXT_TO_HTML_CONVERT_NL) { strcpy (out, "<br>"); out += 4; } *out++ = *cur; linestart = cur; col = 0; break; case '\t': if (flags & (E_TEXT_TO_HTML_CONVERT_SPACES | E_TEXT_TO_HTML_CONVERT_NL)) { do { out = check_size (&buffer, &buffer_size, out, 7); strcpy (out, " "); out += 6; col++; } while (col % 8); break; } /* otherwise, FALL THROUGH */ case ' ': if (flags & E_TEXT_TO_HTML_CONVERT_SPACES) { if (cur == (const guchar *) input || *(cur + 1) == ' ' || *(cur + 1) == '\t' || *(cur - 1) == '\n') { strcpy (out, " "); out += 6; col++; break; } } /* otherwise, FALL THROUGH */ default: if ((u >= 0x20 && u < 0x80) || (u == '\r' || u == '\t')) { /* Default case, just copy. */ *out++ = u; } else { if (flags & E_TEXT_TO_HTML_ESCAPE_8BIT) *out++ = '?'; else out += g_snprintf(out, 9, "&#%d;", u); } col++; break; } } out = check_size (&buffer, &buffer_size, out, 7); if (flags & E_TEXT_TO_HTML_PRE) strcpy (out, "</PRE>"); else *out = '\0'; return buffer; }