source: trunk/dll/errutil.c@ 1373

Last change on this file since 1373 was 1373, checked in by Steven Levine, 17 years ago

Show thread id in DbgMsg

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