+ return val;
+}
+\f
+static Lisp_Object string_char_byte_cache_string;
+static int string_char_byte_cache_charpos;
+static int string_char_byte_cache_bytepos;
+
+/* Return the character index corresponding to CHAR_INDEX in STRING. */
+
+int
+string_char_to_byte (string, char_index)
+ Lisp_Object string;
+ int char_index;
+{
+ int i, i_byte;
+ int best_below, best_below_byte;
+ int best_above, best_above_byte;
+
+ if (! STRING_MULTIBYTE (string))
+ return char_index;
+
+ best_below = best_below_byte = 0;
+ best_above = XSTRING (string)->size;
+ best_above_byte = STRING_BYTES (XSTRING (string));
+
+ if (EQ (string, string_char_byte_cache_string))
+ {
+ if (string_char_byte_cache_charpos < char_index)
+ {
+ best_below = string_char_byte_cache_charpos;
+ best_below_byte = string_char_byte_cache_bytepos;
+ }
+ else
+ {
+ best_above = string_char_byte_cache_charpos;
+ best_above_byte = string_char_byte_cache_bytepos;
+ }
+ }
+
+ if (char_index - best_below < best_above - char_index)
+ {
+ while (best_below < char_index)
+ {
+ int c;
+ FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+ }
+ i = best_below;
+ i_byte = best_below_byte;
+ }
+ else
+ {
+ while (best_above > char_index)
+ {
+ int best_above_byte_saved = --best_above_byte;
+
+ while (best_above_byte > 0
+ && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte]))
+ best_above_byte--;
+ if (XSTRING (string)->data[best_above_byte] < 0x80)
+ best_above_byte = best_above_byte_saved;
+ best_above--;
+ }
+ i = best_above;
+ i_byte = best_above_byte;
+ }
+
+ string_char_byte_cache_bytepos = i_byte;
+ string_char_byte_cache_charpos = i;
+ string_char_byte_cache_string = string;
+
+ return i_byte;
+}
+\f
+/* Return the character index corresponding to BYTE_INDEX in STRING. */
+
+int
+string_byte_to_char (string, byte_index)
+ Lisp_Object string;
+ int byte_index;
+{
+ int i, i_byte;
+ int best_below, best_below_byte;
+ int best_above, best_above_byte;
+
+ if (! STRING_MULTIBYTE (string))
+ return byte_index;
+
+ best_below = best_below_byte = 0;
+ best_above = XSTRING (string)->size;
+ best_above_byte = STRING_BYTES (XSTRING (string));
+
+ if (EQ (string, string_char_byte_cache_string))
+ {
+ if (string_char_byte_cache_bytepos < byte_index)
+ {
+ best_below = string_char_byte_cache_charpos;
+ best_below_byte = string_char_byte_cache_bytepos;
+ }
+ else
+ {
+ best_above = string_char_byte_cache_charpos;
+ best_above_byte = string_char_byte_cache_bytepos;
+ }
+ }
+
+ if (byte_index - best_below_byte < best_above_byte - byte_index)
+ {
+ while (best_below_byte < byte_index)
+ {
+ int c;
+ FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+ }
+ i = best_below;
+ i_byte = best_below_byte;
+ }
+ else
+ {
+ while (best_above_byte > byte_index)
+ {
+ int best_above_byte_saved = --best_above_byte;
+
+ while (best_above_byte > 0
+ && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte]))
+ best_above_byte--;
+ if (XSTRING (string)->data[best_above_byte] < 0x80)
+ best_above_byte = best_above_byte_saved;
+ best_above--;
+ }
+ i = best_above;
+ i_byte = best_above_byte;
+ }
+
+ string_char_byte_cache_bytepos = i_byte;
+ string_char_byte_cache_charpos = i;
+ string_char_byte_cache_string = string;
+
+ return i;
+}
+\f
+/* Convert STRING to a multibyte string.
+ Single-byte characters 0240 through 0377 are converted
+ by adding nonascii_insert_offset to each. */
+
+Lisp_Object
+string_make_multibyte (string)
+ Lisp_Object string;
+{
+ unsigned char *buf;
+ int nbytes;
+
+ if (STRING_MULTIBYTE (string))
+ return string;
+
+ nbytes = count_size_as_multibyte (XSTRING (string)->data,
+ XSTRING (string)->size);
+ /* If all the chars are ASCII, they won't need any more bytes
+ once converted. In that case, we can return STRING itself. */
+ if (nbytes == STRING_BYTES (XSTRING (string)))
+ return string;
+
+ buf = (unsigned char *) alloca (nbytes);
+ copy_text (XSTRING (string)->data, buf, STRING_BYTES (XSTRING (string)),
+ 0, 1);
+
+ return make_multibyte_string (buf, XSTRING (string)->size, nbytes);
+}
+
+/* Convert STRING to a single-byte string. */
+
+Lisp_Object
+string_make_unibyte (string)
+ Lisp_Object string;
+{
+ unsigned char *buf;
+
+ if (! STRING_MULTIBYTE (string))
+ return string;
+
+ buf = (unsigned char *) alloca (XSTRING (string)->size);
+
+ copy_text (XSTRING (string)->data, buf, STRING_BYTES (XSTRING (string)),
+ 1, 0);
+
+ return make_unibyte_string (buf, XSTRING (string)->size);
+}
+
+DEFUN ("string-make-multibyte", Fstring_make_multibyte, Sstring_make_multibyte,
+ 1, 1, 0,
+ "Return the multibyte equivalent of STRING.\n\
+The function `unibyte-char-to-multibyte' is used to convert\n\
+each unibyte character to a multibyte character.")
+ (string)
+ Lisp_Object string;
+{
+ CHECK_STRING (string, 0);
+
+ return string_make_multibyte (string);
+}
+
+DEFUN ("string-make-unibyte", Fstring_make_unibyte, Sstring_make_unibyte,
+ 1, 1, 0,
+ "Return the unibyte equivalent of STRING.\n\
+Multibyte character codes are converted to unibyte\n\
+by using just the low 8 bits.")
+ (string)
+ Lisp_Object string;
+{
+ CHECK_STRING (string, 0);
+
+ return string_make_unibyte (string);
+}
+
+DEFUN ("string-as-unibyte", Fstring_as_unibyte, Sstring_as_unibyte,
+ 1, 1, 0,
+ "Return a unibyte string with the same individual bytes as STRING.\n\
+If STRING is unibyte, the result is STRING itself.")
+ (string)
+ Lisp_Object string;
+{
+ CHECK_STRING (string, 0);
+
+ if (STRING_MULTIBYTE (string))
+ {
+ string = Fcopy_sequence (string);
+ XSTRING (string)->size = STRING_BYTES (XSTRING (string));
+ SET_STRING_BYTES (XSTRING (string), -1);
+ }
+ return string;
+}
+
+DEFUN ("string-as-multibyte", Fstring_as_multibyte, Sstring_as_multibyte,
+ 1, 1, 0,
+ "Return a multibyte string with the same individual bytes as STRING.\n\
+If STRING is multibyte, the result is STRING itself.")
+ (string)
+ Lisp_Object string;
+{
+ CHECK_STRING (string, 0);
+
+ if (! STRING_MULTIBYTE (string))
+ {
+ int nbytes = STRING_BYTES (XSTRING (string));
+ int newlen = multibyte_chars_in_text (XSTRING (string)->data, nbytes);
+
+ string = Fcopy_sequence (string);
+ XSTRING (string)->size = newlen;
+ XSTRING (string)->size_byte = nbytes;
+ }
+ return string;