+/* Evaluating C and C++ expressions. */
+
+/* Convert a UCN. The digits of the UCN start at P and extend no
+ farther than LIMIT. DEST_CHARSET is the name of the character set
+ into which the UCN should be converted. The results are written to
+ OUTPUT. LENGTH is the maximum length of the UCN, either 4 or 8.
+ Returns a pointer to just after the final digit of the UCN. */
+
+static char *
+convert_ucn (char *p, char *limit, const char *dest_charset,
+ struct obstack *output, int length)
+{
+ unsigned long result = 0;
+ gdb_byte data[4];
+ int i;
+
+ for (i = 0; i < length && p < limit && isxdigit (*p); ++i, ++p)
+ result = (result << 4) + host_hex_value (*p);
+
+ for (i = 3; i >= 0; --i)
+ {
+ data[i] = result & 0xff;
+ result >>= 8;
+ }
+
+ convert_between_encodings ("UCS-4BE", dest_charset, data, 4, 4, output,
+ translit_none);
+
+ return p;
+}
+
+/* Emit a character, VALUE, which was specified numerically, to
+ OUTPUT. TYPE is the target character type. */
+
+static void
+emit_numeric_character (struct type *type, unsigned long value,
+ struct obstack *output)
+{
+ gdb_byte *buffer;
+
+ buffer = alloca (TYPE_LENGTH (type));
+ pack_long (buffer, type, value);
+ obstack_grow (output, buffer, TYPE_LENGTH (type));
+}
+
+/* Convert an octal escape sequence. TYPE is the target character
+ type. The digits of the escape sequence begin at P and extend no
+ farther than LIMIT. The result is written to OUTPUT. Returns a
+ pointer to just after the final digit of the escape sequence. */
+
+static char *
+convert_octal (struct type *type, char *p, char *limit, struct obstack *output)
+{
+ int i;
+ unsigned long value = 0;
+
+ for (i = 0;
+ i < 3 && p < limit && isdigit (*p) && *p != '8' && *p != '9';
+ ++i)
+ {
+ value = 8 * value + host_hex_value (*p);
+ ++p;
+ }
+
+ emit_numeric_character (type, value, output);
+
+ return p;
+}
+
+/* Convert a hex escape sequence. TYPE is the target character type.
+ The digits of the escape sequence begin at P and extend no farther
+ than LIMIT. The result is written to OUTPUT. Returns a pointer to
+ just after the final digit of the escape sequence. */
+
+static char *
+convert_hex (struct type *type, char *p, char *limit, struct obstack *output)
+{
+ unsigned long value = 0;
+
+ while (p < limit && isxdigit (*p))
+ {
+ value = 16 * value + host_hex_value (*p);
+ ++p;
+ }
+
+ emit_numeric_character (type, value, output);
+
+ return p;
+}
+
+#define ADVANCE \
+ do { \
+ ++p; \
+ if (p == limit) \
+ error (_("Malformed escape sequence")); \
+ } while (0)
+
+/* Convert an escape sequence to a target format. TYPE is the target
+ character type to use, and DEST_CHARSET is the name of the target
+ character set. The backslash of the escape sequence is at *P, and
+ the escape sequence will not extend past LIMIT. The results are
+ written to OUTPUT. Returns a pointer to just past the final
+ character of the escape sequence. */
+
+static char *
+convert_escape (struct type *type, const char *dest_charset,
+ char *p, char *limit, struct obstack *output)
+{
+ /* Skip the backslash. */
+ ADVANCE;
+
+ switch (*p)
+ {
+ case '\\':
+ obstack_1grow (output, '\\');
+ ++p;
+ break;
+
+ case 'x':
+ ADVANCE;
+ if (!isxdigit (*p))
+ error (_("\\x used with no following hex digits."));
+ p = convert_hex (type, p, limit, output);
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ p = convert_octal (type, p, limit, output);
+ break;
+
+ case 'u':
+ case 'U':
+ {
+ int length = *p == 'u' ? 4 : 8;
+ ADVANCE;
+ if (!isxdigit (*p))
+ error (_("\\u used with no following hex digits"));
+ p = convert_ucn (p, limit, dest_charset, output, length);
+ }
+ }
+
+ return p;
+}
+
+/* Given a single string from a (C-specific) OP_STRING list, convert
+ it to a target string, handling escape sequences specially. The
+ output is written to OUTPUT. DATA is the input string, which has
+ length LEN. DEST_CHARSET is the name of the target character set,
+ and TYPE is the type of target character to use. */
+
+static void
+parse_one_string (struct obstack *output, char *data, int len,
+ const char *dest_charset, struct type *type)
+{
+ char *limit;
+
+ limit = data + len;
+
+ while (data < limit)
+ {
+ char *p = data;
+ /* Look for next escape, or the end of the input. */
+ while (p < limit && *p != '\\')
+ ++p;
+ /* If we saw a run of characters, convert them all. */
+ if (p > data)
+ convert_between_encodings (host_charset (), dest_charset,
+ data, p - data, 1, output, translit_none);
+ /* If we saw an escape, convert it. */
+ if (p < limit)
+ p = convert_escape (type, dest_charset, p, limit, output);
+ data = p;
+ }
+}
+
+/* Expression evaluator for the C language family. Most operations
+ are delegated to evaluate_subexp_standard; see that function for a
+ description of the arguments. */
+
+static struct value *
+evaluate_subexp_c (struct type *expect_type, struct expression *exp,
+ int *pos, enum noside noside)
+{
+ enum exp_opcode op = exp->elts[*pos].opcode;
+
+ switch (op)
+ {
+ case OP_STRING:
+ {
+ int oplen, limit;
+ struct type *type;
+ struct obstack output;
+ struct cleanup *cleanup;
+ struct value *result;
+ enum c_string_type dest_type;
+ const char *dest_charset;
+ enum bfd_endian byte_order;
+
+ obstack_init (&output);
+ cleanup = make_cleanup_obstack_free (&output);
+
+ ++*pos;
+ oplen = longest_to_int (exp->elts[*pos].longconst);
+
+ ++*pos;
+ limit = *pos + BYTES_TO_EXP_ELEM (oplen + 1);
+ dest_type
+ = (enum c_string_type) longest_to_int (exp->elts[*pos].longconst);
+ switch (dest_type & ~C_CHAR)
+ {
+ case C_STRING:
+ type = language_string_char_type (exp->language_defn,
+ exp->gdbarch);
+ break;
+ case C_WIDE_STRING:
+ type = lookup_typename (exp->language_defn, exp->gdbarch,
+ "wchar_t", NULL, 0);
+ break;
+ case C_STRING_16:
+ type = lookup_typename (exp->language_defn, exp->gdbarch,
+ "char16_t", NULL, 0);
+ break;
+ case C_STRING_32:
+ type = lookup_typename (exp->language_defn, exp->gdbarch,
+ "char32_t", NULL, 0);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "unhandled c_string_type");
+ }
+
+ /* Ensure TYPE_LENGTH is valid for TYPE. */
+ check_typedef (type);
+
+ byte_order = gdbarch_byte_order (exp->gdbarch);
+ dest_charset = charset_for_string_type (dest_type, byte_order);
+
+ ++*pos;
+ while (*pos < limit)
+ {
+ int len;
+
+ len = longest_to_int (exp->elts[*pos].longconst);
+
+ ++*pos;
+ if (noside != EVAL_SKIP)
+ parse_one_string (&output, &exp->elts[*pos].string, len,
+ dest_charset, type);
+ *pos += BYTES_TO_EXP_ELEM (len);
+ }
+
+ /* Skip the trailing length and opcode. */
+ *pos += 2;
+
+ if (noside == EVAL_SKIP)
+ {
+ /* Return a dummy value of the appropriate type. */
+ if ((dest_type & C_CHAR) != 0)
+ result = allocate_value (type);
+ else
+ result = value_cstring ("", 0, type);
+ do_cleanups (cleanup);
+ return result;
+ }
+
+ if ((dest_type & C_CHAR) != 0)
+ {
+ LONGEST value;
+
+ if (obstack_object_size (&output) != TYPE_LENGTH (type))
+ error (_("Could not convert character constant to target character set"));
+ value = unpack_long (type, obstack_base (&output));
+ result = value_from_longest (type, value);
+ }
+ else
+ {
+ int i;
+ /* Write the terminating character. */
+ for (i = 0; i < TYPE_LENGTH (type); ++i)
+ obstack_1grow (&output, 0);
+ result = value_cstring (obstack_base (&output),
+ obstack_object_size (&output),
+ type);
+ }
+ do_cleanups (cleanup);
+ return result;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return evaluate_subexp_standard (expect_type, exp, pos, noside);
+}