+void
+msg_location_destroy (struct msg_location *loc)
+{
+ if (loc)
+ {
+ msg_location_uninit (loc);
+ free (loc);
+ }
+}
+
+struct msg_location *
+msg_location_dup (const struct msg_location *src)
+{
+ if (!src)
+ return NULL;
+
+ struct msg_location *dst = xmalloc (sizeof *dst);
+ *dst = (struct msg_location) {
+ .file_name = xstrdup_if_nonnull (src->file_name),
+ .first_line = src->first_line,
+ .last_line = src->last_line,
+ .first_column = src->first_column,
+ .last_column = src->last_column,
+ };
+ return dst;
+}
+
+bool
+msg_location_is_empty (const struct msg_location *loc)
+{
+ return !loc || (!loc->file_name
+ && loc->first_line <= 0
+ && loc->first_column <= 0);
+}
+
+void
+msg_location_format (const struct msg_location *loc, struct string *s)
+{
+ if (!loc)
+ return;
+
+ if (loc->file_name)
+ ds_put_cstr (s, loc->file_name);
+
+ int l1 = loc->first_line;
+ int l2 = MAX (loc->first_line, loc->last_line - 1);
+ int c1 = loc->first_column;
+ int c2 = MAX (loc->first_column, loc->last_column - 1);
+
+ if (l1 > 0)
+ {
+ if (loc->file_name)
+ ds_put_byte (s, ':');
+
+ if (l2 > l1)
+ {
+ if (c1 > 0)
+ ds_put_format (s, "%d.%d-%d.%d", l1, c1, l2, c2);
+ else
+ ds_put_format (s, "%d-%d", l1, l2);
+ }
+ else
+ {
+ if (c1 > 0)
+ {
+ if (c2 > c1)
+ {
+ /* The GNU coding standards say to use
+ LINENO-1.COLUMN-1-COLUMN-2 for this case, but GNU
+ Emacs interprets COLUMN-2 as LINENO-2 if I do that.
+ I've submitted an Emacs bug report:
+ http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7725.
+
+ For now, let's be compatible. */
+ ds_put_format (s, "%d.%d-%d.%d", l1, c1, l1, c2);
+ }
+ else
+ ds_put_format (s, "%d.%d", l1, c1);
+ }
+ else
+ ds_put_format (s, "%d", l1);
+ }
+ }
+ else if (c1 > 0)
+ {
+ if (c2 > c1)
+ ds_put_format (s, ".%d-%d", c1, c2);
+ else
+ ds_put_format (s, ".%d", c1);
+ }
+}
+\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 *
+msg_severity_to_string (enum msg_severity severity)
+{
+ switch (severity)
+ {
+ case MSG_S_ERROR:
+ return _("error");
+ case MSG_S_WARNING:
+ return _("warning");
+ case MSG_S_NOTE:
+ default:
+ return _("note");
+ }
+}