+/* get_prompt: access method for the GDB prompt string. */
+
+#define MAX_PROMPT_SIZE 256
+
+/*
+ * int get_prompt_1 (char * buf);
+ *
+ * Work-horse for get_prompt (called via catch_errors).
+ * Argument is buffer to hold the formatted prompt.
+ *
+ * Returns: 1 for success (use formatted prompt)
+ * 0 for failure (use gdb_prompt_string).
+ */
+
+static int gdb_prompt_escape;
+
+static int
+get_prompt_1 (formatted_prompt)
+ char *formatted_prompt;
+{
+ char *local_prompt;
+
+ if (event_loop_p)
+ local_prompt = PROMPT (0);
+ else
+ local_prompt = gdb_prompt_string;
+
+
+ if (gdb_prompt_escape == 0)
+ {
+ return 0; /* do no formatting */
+ }
+ else
+ /* formatted prompt */
+ {
+ char fmt[40], *promptp, *outp, *tmp;
+ value_ptr arg_val;
+ DOUBLEST doubleval;
+ LONGEST longval;
+ CORE_ADDR addrval;
+
+ int i, len;
+ struct type *arg_type, *elt_type;
+
+ promptp = local_prompt;
+ outp = formatted_prompt;
+
+ while (*promptp != '\0')
+ {
+ int available = MAX_PROMPT_SIZE - (outp - formatted_prompt) - 1;
+
+ if (*promptp != gdb_prompt_escape)
+ {
+ if (available >= 1) /* overflow protect */
+ *outp++ = *promptp++;
+ }
+ else
+ {
+ /* GDB prompt string contains escape char. Parse for arg.
+ Two consecutive escape chars followed by arg followed by
+ a comma means to insert the arg using a default format.
+ Otherwise a printf format string may be included between
+ the two escape chars. eg:
+ %%foo, insert foo using default format
+ %2.2f%foo, insert foo using "%2.2f" format
+ A mismatch between the format string and the data type
+ of "foo" is an error (which we don't know how to protect
+ against). */
+
+ fmt[0] = '\0'; /* assume null format string */
+ if (promptp[1] == gdb_prompt_escape) /* double esc char */
+ {
+ promptp += 2; /* skip past two escape chars. */
+ }
+ else
+ {
+ /* extract format string from between two esc chars */
+ i = 0;
+ do
+ {
+ fmt[i++] = *promptp++; /* copy format string */
+ }
+ while (i < sizeof (fmt) - 1 &&
+ *promptp != gdb_prompt_escape &&
+ *promptp != '\0');
+
+ if (*promptp != gdb_prompt_escape)
+ error ("Syntax error at prompt position %d",
+ promptp - local_prompt);
+ else
+ {
+ promptp++; /* skip second escape char */
+ fmt[i++] = '\0'; /* terminate the format string */
+ }
+ }
+
+ arg_val = parse_to_comma_and_eval (&promptp);
+ if (*promptp == ',')
+ promptp++; /* skip past the comma */
+ arg_type = check_typedef (VALUE_TYPE (arg_val));
+ switch (TYPE_CODE (arg_type))
+ {
+ case TYPE_CODE_ARRAY:
+ elt_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+ if (TYPE_LENGTH (arg_type) > 0 &&
+ TYPE_LENGTH (elt_type) == 1 &&
+ TYPE_CODE (elt_type) == TYPE_CODE_INT)
+ {
+ int len = TYPE_LENGTH (arg_type);
+
+ if (VALUE_LAZY (arg_val))
+ value_fetch_lazy (arg_val);
+ tmp = VALUE_CONTENTS (arg_val);
+
+ if (len > available)
+ len = available; /* overflow protect */
+
+ /* FIXME: how to protect GDB from crashing
+ from bad user-supplied format string? */
+ if (fmt[0] != 0)
+ sprintf (outp, fmt, tmp);
+ else
+ strncpy (outp, tmp, len);
+ outp[len] = '\0';
+ }
+ break;
+ case TYPE_CODE_PTR:
+ elt_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+ addrval = value_as_pointer (arg_val);
+
+ if (TYPE_LENGTH (elt_type) == 1 &&
+ TYPE_CODE (elt_type) == TYPE_CODE_INT &&
+ addrval != 0)
+ {
+ /* display it as a string */
+ char *default_fmt = "%s";
+ char *tmp;
+ int err = 0;
+
+ /* Limiting the number of bytes that the following call
+ will read protects us from sprintf overflow later. */
+ i = target_read_string (addrval, /* src */
+ &tmp, /* dest */
+ available, /* len */
+ &err);
+ if (err) /* read failed */
+ error ("%s on target_read", safe_strerror (err));
+
+ tmp[i] = '\0'; /* force-terminate string */
+ /* FIXME: how to protect GDB from crashing
+ from bad user-supplied format string? */
+ sprintf (outp, fmt[0] == 0 ? default_fmt : fmt,
+ tmp);
+ free (tmp);
+ }
+ else
+ {
+ /* display it as a pointer */
+ char *default_fmt = "0x%x";
+
+ /* FIXME: how to protect GDB from crashing
+ from bad user-supplied format string? */
+ if (available >= 16 /*? */ ) /* overflow protect */
+ sprintf (outp, fmt[0] == 0 ? default_fmt : fmt,
+ (long) addrval);
+ }
+ break;
+ case TYPE_CODE_FLT:
+ {
+ char *default_fmt = "%g";
+
+ doubleval = value_as_double (arg_val);
+ /* FIXME: how to protect GDB from crashing
+ from bad user-supplied format string? */
+ if (available >= 16 /*? */ ) /* overflow protect */
+ sprintf (outp, fmt[0] == 0 ? default_fmt : fmt,
+ (double) doubleval);
+ break;
+ }
+ case TYPE_CODE_INT:
+ {
+ char *default_fmt = "%d";
+
+ longval = value_as_long (arg_val);
+ /* FIXME: how to protect GDB from crashing
+ from bad user-supplied format string? */
+ if (available >= 16 /*? */ ) /* overflow protect */
+ sprintf (outp, fmt[0] == 0 ? default_fmt : fmt,
+ (long) longval);
+ break;
+ }
+ case TYPE_CODE_BOOL:
+ {
+ /* no default format for bool */
+ longval = value_as_long (arg_val);
+ if (available >= 8 /*? */ ) /* overflow protect */
+ {
+ if (longval)
+ strcpy (outp, "<true>");
+ else
+ strcpy (outp, "<false>");
+ }
+ break;
+ }
+ case TYPE_CODE_ENUM:
+ {
+ /* no default format for enum */
+ longval = value_as_long (arg_val);
+ len = TYPE_NFIELDS (arg_type);
+ /* find enum name if possible */
+ for (i = 0; i < len; i++)
+ if (TYPE_FIELD_BITPOS (arg_type, i) == longval)
+ break; /* match -- end loop */
+
+ if (i < len) /* enum name found */
+ {
+ char *name = TYPE_FIELD_NAME (arg_type, i);
+
+ strncpy (outp, name, available);
+ /* in casel available < strlen (name), */
+ outp[available] = '\0';
+ }
+ else
+ {
+ if (available >= 16 /*? */ ) /* overflow protect */
+ sprintf (outp, "%ld", (long) longval);
+ }
+ break;
+ }
+ case TYPE_CODE_VOID:
+ *outp = '\0';
+ break; /* void type -- no output */
+ default:
+ error ("bad data type at prompt position %d",
+ promptp - local_prompt);
+ break;
+ }
+ outp += strlen (outp);
+ }
+ }
+ *outp++ = '\0'; /* terminate prompt string */
+ return 1;
+ }
+}
+
+char *
+get_prompt ()
+{
+ static char buf[MAX_PROMPT_SIZE];
+
+ if (catch_errors (get_prompt_1, buf, "bad formatted prompt: ",
+ RETURN_MASK_ALL))
+ {
+ return &buf[0]; /* successful formatted prompt */
+ }
+ else
+ {
+ /* Prompt could not be formatted. */
+ if (event_loop_p)
+ return PROMPT (0);
+ else
+ return gdb_prompt_string;
+ }
+}