lexer: Change the pipeline to allow more flexible use of macros.
[pspp] / src / libpspp / message.c
index 7d4f9d8430a9ffdd8c008563586aaa6189fbdc50..41a1da17502ea5e18386cdecb5c0d99df2c3afae 100644 (file)
@@ -53,13 +53,13 @@ static int messages_disabled;
 void
 vmsg (enum msg_class class, const char *format, va_list args)
 {
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = msg_class_to_category (class),
     .severity = msg_class_to_severity (class),
     .text = xvasprintf (format, args),
   };
-
-  msg_emit (&m);
+  msg_emit (m);
 }
 
 /* Writes error message in CLASS, with text FORMAT, formatted with
@@ -80,17 +80,18 @@ msg_error (int errnum, const char *format, ...)
 {
   va_list args;
   va_start (args, format);
-  char *e = xvasprintf (format, args);
+  struct string s = DS_EMPTY_INITIALIZER;
+  ds_put_vformat (&s, format, args);
   va_end (args);
+  ds_put_format (&s, ": %s", strerror (errnum));
 
-  struct msg m = {
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
     .category = MSG_C_GENERAL,
     .severity = MSG_S_ERROR,
-    .text = xasprintf (_("%s: %s"), e, strerror (errnum)),
+    .text = ds_steal_cstr (&s),
   };
-  msg_emit (&m);
-
-  free (e);
+  msg_emit (m);
 }
 
 
@@ -104,12 +105,18 @@ msg_set_handler (void (*handler) (const struct msg *, void *aux), void *aux)
 \f
 /* msg_location. */
 
+void
+msg_location_uninit (struct msg_location *loc)
+{
+  free (loc->file_name);
+}
+
 void
 msg_location_destroy (struct msg_location *loc)
 {
   if (loc)
     {
-      free (loc->file_name);
+      msg_location_uninit (loc);
       free (loc);
     }
 }
@@ -196,6 +203,30 @@ msg_location_format (const struct msg_location *loc, struct string *s)
     }
 }
 \f
+/* msg_stack */
+
+void
+msg_stack_destroy (struct msg_stack *stack)
+{
+  if (stack)
+    {
+      msg_location_destroy (stack->location);
+      free (stack->description);
+      free (stack);
+    }
+}
+
+struct msg_stack *
+msg_stack_dup (const struct msg_stack *src)
+{
+  struct msg_stack *dst = xmalloc (sizeof *src);
+  *dst = (struct msg_stack) {
+    .location = msg_location_dup (src->location),
+    .description = xstrdup_if_nonnull (src->description),
+  };
+  return dst;
+}
+\f
 /* Working with messages. */
 
 const char *
@@ -217,10 +248,16 @@ msg_severity_to_string (enum msg_severity severity)
 struct msg *
 msg_dup (const struct msg *src)
 {
+  struct msg_stack **ms = xmalloc (src->n_stack * sizeof *ms);
+  for (size_t i = 0; i < src->n_stack; i++)
+    ms[i] = msg_stack_dup (src->stack[i]);
+
   struct msg *dst = xmalloc (sizeof *dst);
   *dst = (struct msg) {
     .category = src->category,
     .severity = src->severity,
+    .stack = ms,
+    .n_stack = src->n_stack,
     .location = msg_location_dup (src->location),
     .command_name = xstrdup_if_nonnull (src->command_name),
     .text = xstrdup (src->text),
@@ -238,6 +275,9 @@ msg_destroy (struct msg *m)
 {
   if (m)
     {
+      for (size_t i = 0; i < m->n_stack; i++)
+        msg_stack_destroy (m->stack[i]);
+      free (m->stack);
       msg_location_destroy (m->location);
       free (m->text);
       free (m->command_name);
@@ -252,6 +292,16 @@ msg_to_string (const struct msg *m)
 
   ds_init_empty (&s);
 
+  for (size_t i = 0; i < m->n_stack; i++)
+    {
+      const struct msg_stack *ms = m->stack[i];
+      if (!msg_location_is_empty (ms->location))
+        {
+          msg_location_format (ms->location, &s);
+          ds_put_cstr (&s, ": ");
+        }
+      ds_put_format (&s, "%s\n", ms->description);
+    }
   if (m->category != MSG_C_GENERAL && !msg_location_is_empty (m->location))
     {
       msg_location_format (m->location, &s);
@@ -315,10 +365,10 @@ msg_ui_any_errors (void)
 
 
 static void
-ship_message (struct msg *m)
+ship_message (const struct msg *m)
 {
   enum { MAX_STACK = 4 };
-  static struct msg *stack[MAX_STACK];
+  static const struct msg *stack[MAX_STACK];
   static size_t n;
 
   /* If we're recursing on a given message, or recursing deeply, drop it. */
@@ -349,8 +399,6 @@ submit_note (char *s)
   free (s);
 }
 
-
-
 static void
 process_msg (struct msg *m)
 {
@@ -391,16 +439,13 @@ process_msg (struct msg *m)
 }
 
 
-/* Emits M as an error message.
-   Frees allocated data in M. */
+/* Emits M as an error message.  Takes ownership of M. */
 void
 msg_emit (struct msg *m)
 {
   if (!messages_disabled)
-     process_msg (m);
-
-  free (m->text);
-  free (m->command_name);
+    process_msg (m);
+  msg_destroy (m);
 }
 
 /* Disables message output until the next call to msg_enable.  If