chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / werr
1 /*
2  * werr
3  *  Just like the old one, only nicer.
4  *
5  * v. 1.00 (8 Aug 1993)
6  *
7  * © 1993-1998 Straylight
8  */
9
10 /*----- Licensing note ----------------------------------------------------*
11  *
12  * This file is part of Straylight's Steel library.
13  *
14  * Steel is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2, or (at your option)
17  * any later version.
18  *
19  * Steel is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with Steel.  If not, write to the Free Software Foundation,
26  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #include "werr.h"
30 #include "dbox.h"
31 #include "template.h"
32 #include "nopoll.h"
33 #include "bbc.h"
34 #include "wimp.h"
35 #include "wimpt.h"
36 #include "win.h"
37 #include "msgs.h"
38 #include "kernel.h"
39 #include "swiv.h"
40 #include "swis.h"
41 #include "exception.h"
42 #include "calltrace.h"
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <stdio.h>
47
48 #define werr__TITLE 0
49 #define werr__OK 3
50 #define werr__CANCEL 6
51 #define werr__ERROR 4
52 #define werr__BACKTRACE 7
53
54 static dbox werr__errorBox;
55 static BOOL werr__initialised;
56
57 /*
58  * void werr_bleepy(void)
59  *
60  * Use
61  *  Bleeps if and only if the appropriate WimpFlags bit is right for
62  *  bleeping.
63  */
64
65 void werr_bleepy(void)
66 {
67   int bleepy=_kernel_osbyte(161,197,0);
68   if (bleepy>0)
69   {
70     if ((bleepy&4096)==0)
71       bbc_vdu(7);
72   }
73 }
74
75 /*
76  * void werr_init(void)
77  *
78  * Use
79  *  Sets up the werr system ready for action.
80  */
81
82 void werr_init(void)
83 {
84   char *title=template_syshandle("error")->title.indirecttext.buffer;
85   if (!win_anyWindows())
86   {
87     werr(FALSE,msgs_lookup("werrSEM:Could not initialise."));
88     exit(0);
89   }
90   sprintf(title,"Error from %s",wimpt_programname());
91   werr__errorBox=dbox_create("error");
92   werr__initialised=TRUE;
93 }
94
95 /*
96  * wimp_icon *werr__idef(wimp_wind *w,wimp_i i)
97  *
98  * Use
99  *  Vaguely similar to the dbox version, only different.  Returns a pointer
100  *  to the icon, at any rate.
101  *
102  * Parameters
103  *  wimp_wind *w == the window definition.
104  *  wimp_i i == the icon number
105  *
106  * Returns
107  *  Pointer to the icon definition.
108  */
109
110 static wimp_icon *werr__idef(wimp_wind *w,wimp_i i)
111 {
112   return ((wimp_icon *)(w+1)+i);
113 }
114
115 /*
116  * int werr__wimpBox(char *string,int buttons)
117  *
118  * Use
119  *  Displays a WIMP error box to show the specified message
120  *
121  * Parameters
122  *  char *string == the error string to display
123  *  int buttons == the number of buttons to display
124  */
125
126 static int werr__wimpBox(char *string,int buttons)
127 {
128   os_error err;
129   static BOOL threaded;
130   int f;
131
132   /* --- If we crashed in here before, abort damned quick --- */
133
134   if (threaded)
135   {
136     _swi(Wimp_CommandWindow,_in(0),"Unrecoverable error");
137     fprintf(stderr,
138             "%s has suffered a fatal error and must quit.",
139             wimpt_programname());
140     abort();
141   }
142
143   /* --- Display the error message --- */
144
145   threaded=TRUE;
146   strcpy(err.errmess,string);
147   err.errnum=1;    /* Stop new WindowManglers thinking this is serious :-/ */
148   if (buttons==1)
149     f=wimp_EOK;
150   else
151     f=wimp_EOK | wimp_ECANCEL;
152   f=_swi(Wimp_ReportError,_inr(0,2)+_return(1),&err,f,wimpt_programname());
153   threaded=FALSE;
154
155   return (f==2 ? 0 : 1);
156 }
157
158 /*
159  * int werr__reportError(int buttons,char *error,va_list ap)
160  *
161  * Use
162  *  Error reporting primitive.  Called by all both the old and new werr()s.
163  *
164  * Parameters
165  *  int buttons == how many buttons we need (1 or 2)
166  *  char *error == a printf() type format string for the error text
167  *  va_list ap == the variable arg list to use.
168  *
169  * Returns
170  *  1 if OK clicked, 0 if Cancel clicked.
171  */
172
173 static int werr__reportError(int buttons,char *error,va_list ap)
174 {
175   wimp_wind *wind;
176   wimp_icon *ok;
177   wimp_icon *cancel;
178   wimp_icon *backtrace=(wimp_icon *)(-80);
179   int cancelButt=-1;
180   int backButt=-1;
181   int clicked;
182   char errString[256];
183   BOOL hasBacktrace;
184
185   /* --- Set up the dialogue box --- */
186
187   vsprintf(errString,error,ap);
188   if (werr__initialised==FALSE)
189     return (werr__wimpBox(errString,buttons));
190
191   /* --- Find all the definitions we need --- */
192
193   werr__initialised=FALSE;               /* Use the WIMP box if this fails */
194   wind=template_syshandle("error");
195   hasBacktrace=(wind->nicons>=werr__BACKTRACE);
196   ok=werr__idef(wind,werr__OK);
197   cancel=werr__idef(wind,werr__CANCEL);
198   if (hasBacktrace)
199     backtrace=werr__idef(wind,werr__BACKTRACE);
200   dbox_delete(werr__errorBox);
201
202   /* --- Zap any unwanted buttons --- */
203
204   if (buttons>=2)
205   {
206     cancel->flags&=~(1<<23);
207     cancelButt=werr__CANCEL;
208   }
209   else
210     cancel->flags|=(1<<23);
211
212   if (hasBacktrace)
213   {
214     if (buttons>=3)
215     {
216       backtrace->flags&=~(1<<23);
217       backButt=werr__BACKTRACE;
218     }
219     else
220       backtrace->flags|=(1<<23);
221   }
222
223   /* --- Display the error box on the screen --- */
224
225   werr__errorBox=dbox_create("error");
226   if (!werr__errorBox)
227     return (werr__wimpBox(errString,buttons));
228   if (!dbox_hasTitle(werr__errorBox))
229     dbox_setEmbeddedTitle(werr__errorBox,werr__TITLE,FALSE);
230   dbox_setfield(werr__errorBox,werr__ERROR,"%s",errString);
231
232   /* --- Display backtraces for as long we're asked to --- */
233
234   werr_bleepy();
235   do
236   {
237     clicked=nopoll_doDbox(werr__errorBox,
238                           nopoll_CENTRE,
239                           werr__OK,
240                           cancelButt,
241                           backButt);
242     if (clicked==nopoll_OTHER)
243       _calltrace();
244   }
245   while (clicked==nopoll_OTHER);
246
247   /* --- Return the result to the user --- */
248
249   werr__initialised=TRUE;                /* Use fancy box for next error   */
250   return (clicked==nopoll_OK);
251 }
252
253 /*
254  * void werr(int fatal,char *error,...)
255  *
256  * Use
257  *  Compatibility with the old werr segment mainly.  If the error is fatal,
258  *  a STEEL exception is generated, which eventually gets round to the
259  *  error box handlers and dumps back out to top level.
260  *
261  * Parameters
262  *  int fatal == 1 if the error is fatal, or 0 otherwise.
263  *  char *error == printf()-type format string.
264  */
265
266 void werr(int fatal,char *error,...)
267 {
268   va_list ap;
269   va_start(ap,error);
270   if (fatal==0)
271   {
272     werr__reportError(1,error,ap);
273     va_end(ap);
274   }
275   else
276   {
277     char buffer[256];
278     vsprintf(buffer,error,ap);
279     va_end(ap);
280     exception_generate("%s",buffer);
281   }
282 }
283
284 /*
285  * int werr_error(int buttons,char *error,...)
286  *
287  * Use
288  *  Reports an error.  You can have two buttons, OK and Cancel if you really
289  *  want, now.
290  *
291  * Parameters
292  *  int buttons == 1 for 1 button, 2 for 2 buttons, or anything else for an
293  *    unpredictable result.
294  *  char *error == printf()-like format string.
295  *
296  * Returns
297  *  1 for OK, 0 for cancel.
298  */
299
300 int werr_error(int buttons,char *error,...)
301 {
302   va_list ap;
303   int clicked;
304   va_start(ap,error);
305   clicked=werr__reportError(buttons,error,ap);
306   va_end(ap);
307   return (clicked);
308 }