c227a60368a0ff725dacc9baba4e00bf916cf37d
[pspp-builds.git] / src / libpspp / message.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "message.h"
20 #include "msg-locator.h"
21
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <libpspp/str.h>
30 #include <libpspp/version.h>
31
32 #include "gl/progname.h"
33 #include "gl/xalloc.h"
34 #include "gl/xvasprintf.h"
35
36 #include "gettext.h"
37 #define _(msgid) gettext (msgid)
38
39 /* Message handler as set by msg_init(). */
40 static void (*msg_handler)  (const struct msg *);
41
42 /* Disables emitting messages if positive. */
43 static int messages_disabled;
44
45 /* Public functions. */
46
47 /* Writes error message in CLASS, with text FORMAT, formatted with
48    printf, to the standard places. */
49 void
50 msg (enum msg_class class, const char *format, ...)
51 {
52   struct msg m;
53   va_list args;
54
55   m.category = msg_class_to_category (class);
56   m.severity = msg_class_to_severity (class);
57   va_start (args, format);
58   m.text = xvasprintf (format, args);
59   va_end (args);
60
61   msg_emit (&m);
62 }
63
64 static struct source_stream *s_stream;
65
66 void
67 msg_init (struct source_stream *ss,  void (*handler) (const struct msg *) )
68 {
69   s_stream = ss;
70   msg_handler = handler;
71 }
72
73 void
74 msg_done (void)
75 {
76 }
77 \f
78 /* Working with messages. */
79
80 /* Duplicate a message */
81 struct msg *
82 msg_dup (const struct msg *m)
83 {
84   struct msg *new_msg;
85
86   new_msg = xmemdup (m, sizeof *m);
87   if (m->where.file_name != NULL)
88     new_msg->where.file_name = xstrdup (m->where.file_name);
89   new_msg->text = xstrdup (m->text);
90
91   return new_msg;
92 }
93
94 /* Frees a message created by msg_dup().
95
96    (Messages not created by msg_dup(), as well as their where.file_name
97    members, are typically not dynamically allocated, so this function should
98    not be used to destroy them.) */
99 void
100 msg_destroy (struct msg *m)
101 {
102   free (m->where.file_name);
103   free (m->text);
104   free (m);
105 }
106
107 char *
108 msg_to_string (const struct msg *m, const char *command_name)
109 {
110   const char *label;
111   struct string s;
112
113   ds_init_empty (&s);
114
115   if (m->category != MSG_C_GENERAL
116       && (m->where.file_name || m->where.line_number != -1))
117     {
118       if (m->where.file_name)
119         ds_put_format (&s, "%s:", m->where.file_name);
120       if (m->where.line_number != -1)
121         ds_put_format (&s, "%d:", m->where.line_number);
122       ds_put_char (&s, ' ');
123     }
124
125   switch (m->severity)
126     {
127     case MSG_S_ERROR:
128       label = _("error");
129       break;
130     case MSG_S_WARNING:
131       label = _("warning");
132       break;
133     case MSG_S_NOTE:
134     default:
135       label = _("note");
136       break;
137     }
138   ds_put_format (&s, "%s: ", label);
139
140   if (m->category == MSG_C_SYNTAX && command_name != NULL)
141     ds_put_format (&s, "%s: ", command_name);
142
143   ds_put_cstr (&s, m->text);
144
145   return ds_cstr (&s);
146 }
147 \f
148 /* Emits M as an error message.
149    Frees allocated data in M. */
150 void
151 msg_emit (struct msg *m)
152 {
153   if ( s_stream )
154     get_msg_location (s_stream, &m->where);
155   else
156     {
157       m->where.file_name = NULL;
158       m->where.line_number = -1;
159     }
160
161   if (!messages_disabled)
162      msg_handler (m);
163   free (m->text);
164 }
165
166 /* Disables message output until the next call to msg_enable.  If
167    this function is called multiple times, msg_enable must be
168    called an equal number of times before messages are actually
169    re-enabled. */
170 void
171 msg_disable (void)
172 {
173   messages_disabled++;
174 }
175
176 /* Enables message output that was disabled by msg_disable. */
177 void
178 msg_enable (void)
179 {
180   assert (messages_disabled > 0);
181   messages_disabled--;
182 }
183 \f
184 /* Private functions. */
185
186 void
187 request_bug_report_and_abort (const char *msg)
188 {
189   fprintf (stderr, "******************************************************\n");
190   fprintf (stderr, "You have discovered a bug in PSPP.  Please report this\n");
191   fprintf (stderr, "to " PACKAGE_BUGREPORT ".  Please include this entire\n");
192   fprintf (stderr, "message, *plus* several lines of output just above it.\n");
193   fprintf (stderr, "For the best chance at having the bug fixed, also\n");
194   fprintf (stderr, "include the syntax file that triggered it and a sample\n");
195   fprintf (stderr, "of any data file used for input.\n");
196   fprintf (stderr, "proximate cause:     %s\n", msg);
197   fprintf (stderr, "version:             %s\n", stat_version);
198   fprintf (stderr, "host_system:         %s\n", host_system);
199   fprintf (stderr, "build_system:        %s\n", build_system);
200   fprintf (stderr, "locale_dir:          %s\n", locale_dir);
201   fprintf (stderr, "compiler version:    %s\n",
202 #ifdef __VERSION__
203            __VERSION__
204 #else
205            "Unknown"
206 #endif
207            );
208   fprintf (stderr, "******************************************************\n");
209
210   _exit (EXIT_FAILURE);
211 }