source: trunk/dll/errutil.c@ 1397

Last change on this file since 1397 was 1395, checked in by Gregg Young, 17 years ago

Allow user to turn off alert and/or error beeps in settings notebook. Ticket 341 Move repeated strings to PCSZs. Ticket 6 Add *DateFormat functions to format dates based on locale Ticket 28 Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error Ticket 6

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1
2/***********************************************************************
3
4 $Id: errutil.c 1395 2009-02-08 01:48:16Z gyoung $
5
6 Error reporting
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2004, 2008 Steven H. Levine
10
11 12 Aug 04 SHL Comments
12 23 May 05 SHL Move saymsg here
13 24 May 05 SHL Rename General_Error to more accurate Win_Error
14 24 May 05 SHL Rename saymsg to more accurate Misc_Error
15 24 May 05 SHL Rework Win_Error args and clean up logic
16 27 May 05 SHL Rework to use common showMsg
17 14 Aug 05 SHL showMsg: suppress write to stdout if not error message
18 13 Jul 06 SHL Add Runtime_Error
19 22 Jul 06 SHL Optimize calling sequences
20 26 Jul 06 SHL Add ..._Error2
21 16 Aug 06 SHL Tweak message formatting
22 07 Jan 07 GKY Move error strings etc. to string file
23 18 Apr 07 SHL showMsg: correct selective logging checks
24 19 Apr 07 SHL Add DbgMsg
25 20 Apr 07 SHL Correct IDS_GENERR1TEXT formatting
26 23 Apr 07 SHL Add Win_Error_NoMsgBox. Rework others
27 14 Aug 07 SHL Add GetMSecTimer
28 14 Aug 07 SHL Use GetMSecTimer in DbgMsg
29 05 Jan 08 SHL Renamed from error.c to match errutil.h
30 18 Dec 08 SHL Show thread id in DbgMsg
31 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
32 07 Feb 09 GKY Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error
33 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
34
35***********************************************************************/
36
37#include <stdio.h>
38#include <string.h>
39#include <stdarg.h>
40
41#define INCL_DOS
42#define INCL_WIN
43#define INCL_DOSERRORS
44#define INCL_DOSPROCESS // PPIB PTIB
45#define INCL_LONGLONG
46
47#include "errutil.h"
48#include "strutil.h" // GetPString
49#include "fm3str.h"
50#include "notebook.h" // fErrorBeepOff
51
52#pragma data_seg(GLOBAL2)
53PSZ DEBUG_STRING;
54
55#pragma data_seg(DATA1)
56
57static PSZ pszSrcFile = __FILE__;
58
59static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
60 PCSZ pszSrcFile, UINT uSrcLineNo,
61 PCSZ pszFmt, va_list pva);
62
63static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
64
65//=== DbgMsg: output debug message stderr ===
66
67VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
68{
69 PIB *ppib;
70 TIB *ptib;
71 ULONG ultid;
72 APIRET apiret;
73 va_list va;
74
75#if 1 // fixme to be selectable
76
77 static ULONG ul1stMSec;
78 // static ULONG ulLastMSec;
79
80 ULONG msec = GetMSecTimer();
81 ULONG delta;
82
83 if (!ul1stMSec) {
84 ul1stMSec = msec;
85 // ulLastMSec = msec; // Avoid big delta 1st time
86 }
87
88 delta = msec - ul1stMSec;
89 // ulLastMSec = msec;
90 fprintf(stderr, "%03lu.%03lu ", delta / 1000, delta % 1000);
91
92#endif
93
94 apiret = DosGetInfoBlocks(&ptib, &ppib);
95 if (apiret)
96 ultid = 0;
97 else
98 ultid = ptib->tib_ptib2->tib2_ultid;
99
100 // OK for source file name to be null
101 fprintf(stderr, "%s %u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
102 // If format null want just file and line
103 if (pszFmt) {
104 fputc(' ', stderr);
105 va_start(va, pszFmt);
106 vfprintf(stderr, pszFmt, va);
107 va_end(va);
108 }
109 fputc('\n', stderr);
110 fflush(stderr);
111
112} // DbgMsg
113
114//== Dos_Error: report Dos...() error using passed message string ===
115
116INT Dos_Error(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
117 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
118{
119 CHAR szMsg[4096];
120 ULONG Class; // Error class
121 ULONG action; // Error action
122 ULONG Locus; // Error location
123 ULONG ulMsgLen;
124 CHAR *pszMsgStart;
125 CHAR *psz;
126 va_list va;
127
128 if (!ulRC)
129 return MBID_ENTER; // Should not have been called
130
131 // Format caller's message
132 va_start(va, pszFmt);
133 szMsg[sizeof(szMsg) - 1] = 0;
134 vsprintf(szMsg, pszFmt, va);
135 va_end(va);
136
137 if (szMsg[sizeof(szMsg) - 1]) {
138 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
139 fflush(stderr);
140 }
141
142 if (strchr(szMsg, ' ') == NULL) {
143 strcat(szMsg, " ");
144 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
145 }
146
147 DosErrClass(ulRC, &Class, &action, &Locus);
148
149 sprintf(szMsg + strlen(szMsg),
150 GetPString(IDS_DOSERR1TEXT),
151 pszSrcFile,
152 uSrcLineNo,
153 ulRC,
154 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
155 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
156 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
157 pszMsgStart = szMsg + strlen(szMsg) + 1;
158 // Get message leaving space for NL separator
159 if (!DosGetMessage
160 (NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC, "OSO001.MSG", &ulMsgLen)
161 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC,
162 "OSO001H.MSG", &ulMsgLen)) {
163 // Got message
164 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
165 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
166 *pszMsgStart = '\"'; // Prefix message text with quote
167
168 psz = pszMsgStart + ulMsgLen; // Point at last char
169 // Chop trailing NL CR TAB
170 while (*psz &&
171 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
172 *psz-- = 0;
173 }
174 strcat(psz, "\""); // Append trailing quote
175
176 // Convert CR and NL combos to single space
177 psz = pszMsgStart;
178 while (*psz) {
179 if (*psz == '\n' || *psz == '\r') {
180 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
181 memmove(psz, psz + 1, strlen(psz));
182 *psz = ' ';
183 }
184 else
185 psz++;
186 }
187 }
188
189 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
190 szMsg, TRUE);
191
192} // Dos_Error
193
194/*== Dos_Error2: report Dos...() error using passed message id ===
195
196INT Dos_Error2(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
197 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
198{
199 return Dos_Error(mb_type, ulRC, hwndOwner, pszSrcFile, uSrcLineNo,
200 GetPString(idMsg));
201} // Dos_Error2 */
202
203/**
204 * Format last PM error into passed buffer
205 */
206
207static VOID formatWinError(PSZ pszBuf, UINT cBufBytes,
208 HWND hwndErr, HWND hwndOwner,
209 PCSZ pszSrcFile, UINT uSrcLineNo,
210 PCSZ pszFmt, va_list pva)
211{
212 PERRINFO pErrInfoBlk; /* Pointer to ERRINFO structure filled
213 by WinGetErrorInfo */
214 PSZ pszOffset; /* Pointer to current error message returned
215 by WinGetErrorInfo */
216 PSZ psz;
217 HAB hab;
218
219 if (hwndErr == NULLHANDLE)
220 hab = (HAB)0;
221 else
222 hab = WinQueryAnchorBlock(hwndErr);
223
224 // Format callers message
225 pszBuf[cBufBytes - 1] = 0;
226 vsprintf(pszBuf, pszFmt, pva);
227
228 if (pszBuf[cBufBytes - 1]) {
229 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
230 fflush(stderr);
231 }
232
233 if (strchr(pszBuf, ' ') == NULL) {
234 strcat(pszBuf, " ");
235 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
236 }
237
238 // Append file name and line number and trailing space
239 sprintf(pszBuf + strlen(pszBuf),
240 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
241
242 // Get last PM error for the current thread
243 pErrInfoBlk = WinGetErrorInfo(hab);
244 if (!pErrInfoBlk) {
245 ERRORID id = WinGetLastError(hab);
246 psz = pszBuf + strlen(pszBuf);
247 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
248 }
249 else {
250 if (!hwndOwner)
251 hwndOwner = HWND_DESKTOP;
252 /* Find message offset in array of message offsets
253 Assume 1 message - fixme?
254 */
255 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
256 /* Address error message in array of messages and
257 append error message to source code linenumber
258 */
259 psz = pszBuf + strlen(pszBuf);
260 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
261 psz += strlen(psz);
262 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
263 psz += strlen(psz);
264 // Chop trailing mush
265 psz--;
266 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
267 *psz-- = 0;
268 if (*psz)
269 psz++;
270 strcpy(psz, "\"");
271 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
272 }
273
274} // formatWinError
275
276/**
277 * Return millisecond timer value
278 * Resolution is milliseconds, but accuracy will be less
279 * depending on systems settings
280 */
281
282ULONG GetMSecTimer(void)
283{
284 ULONG msec;
285
286 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
287 &msec, sizeof(msec));
288 if (rc) {
289 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
290 "DosQuerySysInfo");
291 msec = 0;
292 }
293 return msec;
294}
295
296//== Runtime_Error: report runtime library error using passed message string ===
297
298VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
299{
300 CHAR szMsg[4096];
301 va_list va;
302
303 // Format caller's message
304 va_start(va, pszFmt);
305 szMsg[sizeof(szMsg) - 1] = 0;
306 vsprintf(szMsg, pszFmt, va);
307 va_end(va);
308
309 if (szMsg[sizeof(szMsg) - 1]) {
310 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
311 fflush(stderr);
312 }
313
314 if (strchr(szMsg, ' ') == NULL) {
315 strcat(szMsg, " ");
316 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
317 }
318
319 sprintf(szMsg + strlen(szMsg),
320 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
321
322 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
323
324} // Runtime_Error
325
326//== Runtime_Error2: report runtime library error using passed message id ===
327
328VOID Runtime_Error2(PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
329{
330 Runtime_Error(pszSrcFile, uSrcLineNo, GetPString(idMsg));
331
332} // Runtime_Error2
333
334// fixme to be rename to Misc_Error
335
336//=== saymsg: report misc error using passed message ===
337
338APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
339{
340 CHAR szMsg[4096];
341 va_list va;
342
343 va_start(va, pszFmt);
344 szMsg[sizeof(szMsg) - 1] = 0;
345 vsprintf(szMsg, pszFmt, va);
346 va_end(va);
347
348 if (szMsg[sizeof(szMsg) - 1]) {
349 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
350 fflush(stderr);
351 }
352
353 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
354
355} // saymsg
356
357//=== showMsg: display error popup ===
358
359static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
360 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
361{
362 if (wantLog) {
363 fputs(pszMsg, stderr);
364 fputc('\n', stderr);
365 fputc('\n', stderr);
366 fflush(stderr);
367 }
368
369 if (!hwndOwner)
370 hwndOwner = HWND_DESKTOP;
371 if (!fErrorBeepOff)
372 DosBeep(250, 100);
373
374 return WinMessageBox(HWND_DESKTOP, // Parent
375 hwndOwner,
376 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
377 mb_type | MB_MOVEABLE);
378} // showMsg
379
380//== Win_Error: report Win...() error using passed message string ===
381
382VOID Win_Error(HWND hwndErr, HWND hwndOwner,
383 PCSZ pszSrcFile, UINT uSrcLineNo,
384 PCSZ pszFmt, ...)
385{
386 CHAR szMsg[4096];
387 va_list va;
388
389 // Format callers message
390 va_start(va, pszFmt);
391 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
392 va_end(va);
393
394 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
395 szMsg, TRUE);
396
397} // Win_Error
398
399/*== Win_Error2: report Win...() error using passed message id ===
400
401VOID Win_Error2(HWND hwndErr, HWND hwndOwner,
402 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
403{
404 Win_Error(hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, GetPString(idMsg));
405
406} // Win_Error2 */
407
408/**
409 * Output PM error messsage to stderr
410 * This does to same reporting as Win_Error, but bypasses the
411 * message box popup.
412 * Use this version when the popup would hang PM.
413 */
414
415VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
416 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
417{
418 CHAR szMsg[4096];
419 va_list va;
420
421 // Format callers message
422 va_start(va, pszFmt);
423 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
424 va_end(va);
425
426 fputs(szMsg, stderr);
427 fputc('\n', stderr);
428 fputc('\n', stderr);
429 fflush(stderr);
430 if (!fErrorBeepOff)
431 DosBeep(250, 100);
432
433} // Win_Error_NoMsgBox
434
435#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,GetHiresTimeer)
Note: See TracBrowser for help on using the repository browser.