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
RevLine 
[121]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
[907]9 Copyright (c) 2004, 2008 Steven H. Levine
[121]10
[137]11 12 Aug 04 SHL Comments
12 23 May 05 SHL Move saymsg here
[144]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
[182]16 27 May 05 SHL Rework to use common showMsg
[258]17 14 Aug 05 SHL showMsg: suppress write to stdout if not error message
[327]18 13 Jul 06 SHL Add Runtime_Error
19 22 Jul 06 SHL Optimize calling sequences
[383]20 26 Jul 06 SHL Add ..._Error2
[452]21 16 Aug 06 SHL Tweak message formatting
[552]22 07 Jan 07 GKY Move error strings etc. to string file
[613]23 18 Apr 07 SHL showMsg: correct selective logging checks
[616]24 19 Apr 07 SHL Add DbgMsg
25 20 Apr 07 SHL Correct IDS_GENERR1TEXT formatting
[636]26 23 Apr 07 SHL Add Win_Error_NoMsgBox. Rework others
[787]27 14 Aug 07 SHL Add GetMSecTimer
28 14 Aug 07 SHL Use GetMSecTimer in DbgMsg
[907]29 05 Jan 08 SHL Renamed from error.c to match errutil.h
[1373]30 18 Dec 08 SHL Show thread id in DbgMsg
[121]31
32***********************************************************************/
33
[907]34#include <stdio.h>
35#include <string.h>
36#include <stdarg.h>
37
[2]38#define INCL_DOS
[1373]39#define INCL_WIN
[2]40#define INCL_DOSERRORS
[1373]41#define INCL_DOSPROCESS // PPIB PTIB
[2]42
[907]43#include "errutil.h"
44#include "strutil.h" // GetPString
[2]45#include "fm3str.h"
46
[907]47#pragma data_seg(GLOBAL2)
48PSZ DEBUG_STRING;
49
[2]50#pragma data_seg(DATA1)
51
[787]52static PSZ pszSrcFile = __FILE__;
53
[636]54static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
55 PCSZ pszSrcFile, UINT uSrcLineNo,
56 PCSZ pszFmt, va_list pva);
57
[613]58static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
[2]59
[636]60//=== DbgMsg: output debug message stderr ===
[144]61
[636]62VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]63{
[1373]64 PIB *ppib;
65 TIB *ptib;
66 ULONG ultid;
67 APIRET apiret;
[144]68 va_list va;
[2]69
[787]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
[1373]89 apiret = DosGetInfoBlocks(&ptib, &ppib);
90 if (apiret)
91 ultid = 0;
92 else
93 ultid = ptib->tib_ptib2->tib2_ultid;
94
[636]95 // OK for source file name to be null
[1373]96 fprintf(stderr, "%s %u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
[636]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);
[613]103 }
[636]104 fputc('\n', stderr);
105 fflush(stderr);
[613]106
[636]107} // DbgMsg
[327]108
[452]109//== Dos_Error: report Dos...() error using passed message string ===
[144]110
[636]111INT Dos_Error(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
112 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]113{
[182]114 CHAR szMsg[4096];
[636]115 ULONG Class; // Error class
116 ULONG action; // Error action
117 ULONG Locus; // Error location
[144]118 ULONG ulMsgLen;
119 CHAR *pszMsgStart;
120 CHAR *psz;
121 va_list va;
[2]122
[144]123 if (!ulRC)
124 return MBID_ENTER; // Should not have been called
[121]125
[144]126 // Format caller's message
127 va_start(va, pszFmt);
[613]128 szMsg[sizeof(szMsg) - 1] = 0;
[182]129 vsprintf(szMsg, pszFmt, va);
[144]130 va_end(va);
[121]131
[613]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
[327]137 if (strchr(szMsg, ' ') == NULL)
[636]138 strcat(szMsg, " failed"); // Assume simple function name
[327]139
[144]140 DosErrClass(ulRC, &Class, &action, &Locus);
141
[182]142 sprintf(szMsg + strlen(szMsg),
[144]143 GetPString(IDS_DOSERR1TEXT),
[636]144 pszSrcFile,
145 uSrcLineNo,
[144]146 ulRC,
147 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
148 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
149 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
[182]150 pszMsgStart = szMsg + strlen(szMsg) + 1;
[144]151 // Get message leaving space for NL separator
[551]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)) {
[144]156 // Got message
157 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
[182]158 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
[144]159 *pszMsgStart = '\"'; // Prefix message text with quote
[182]160
[144]161 psz = pszMsgStart + ulMsgLen; // Point at last char
162 // Chop trailing NL CR TAB
163 while (*psz &&
[551]164 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
[144]165 *psz-- = 0;
166 }
167 strcat(psz, "\""); // Append trailing quote
168
169 // Convert CR and NL combos to single space
170 psz = pszMsgStart;
[551]171 while (*psz) {
172 if (*psz == '\n' || *psz == '\r') {
[144]173 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
174 memmove(psz, psz + 1, strlen(psz));
175 *psz = ' ';
[2]176 }
[144]177 else
178 psz++;
[2]179 }
180 }
[137]181
[613]182 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
183 szMsg, TRUE);
[137]184
[636]185} // Dos_Error
[137]186
[452]187//== Dos_Error2: report Dos...() error using passed message id ===
[383]188
[636]189INT Dos_Error2(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
190 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
[383]191{
[636]192 return Dos_Error(mb_type, ulRC, hwndOwner, pszSrcFile, uSrcLineNo,
[551]193 GetPString(idMsg));
[636]194} // Dos_Error2
[383]195
[636]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) {
[907]236 ERRORID id = WinGetLastError(hab);
[636]237 psz = pszBuf + strlen(pszBuf);
[904]238 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]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);
[904]251 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]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
[787]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
[452]287//== Runtime_Error: report runtime library error using passed message string ===
[327]288
[551]289VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]290{
291 CHAR szMsg[4096];
292 va_list va;
293
294 // Format caller's message
295 va_start(va, pszFmt);
[613]296 szMsg[sizeof(szMsg) - 1] = 0;
[327]297 vsprintf(szMsg, pszFmt, va);
298 va_end(va);
299
[613]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
[327]305 if (strchr(szMsg, ' ') == NULL)
[636]306 strcat(szMsg, " failed"); // Assume simple function name
[327]307
308 sprintf(szMsg + strlen(szMsg),
[613]309 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]310
[613]311 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, DEBUG_STRING, szMsg, TRUE);
[327]312
[636]313} // Runtime_Error
[327]314
[452]315//== Runtime_Error2: report runtime library error using passed message id ===
316
[383]317VOID Runtime_Error2(PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
318{
319 Runtime_Error(pszSrcFile, uSrcLineNo, GetPString(idMsg));
320
[636]321} // Runtime_Error2
[383]322
[182]323// fixme to be rename to Misc_Error
[144]324
[452]325//=== saymsg: report misc error using passed message ===
[144]326
[551]327APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]328{
[182]329 CHAR szMsg[4096];
[144]330 va_list va;
[137]331
[144]332 va_start(va, pszFmt);
[613]333 szMsg[sizeof(szMsg) - 1] = 0;
[182]334 vsprintf(szMsg, pszFmt, va);
[144]335 va_end(va);
336
[613]337 if (szMsg[sizeof(szMsg) - 1]) {
338 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
339 fflush(stderr);
340 }
[452]341
[613]342 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
343
[636]344} // saymsg
[182]345
[452]346//=== showMsg: display error popup ===
[182]347
[636]348static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
349 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]350{
[613]351 if (wantLog) {
[258]352 fputs(pszMsg, stderr);
353 fputc('\n', stderr);
[614]354 fputc('\n', stderr);
[258]355 fflush(stderr);
356 }
357
[616]358 if (!hwndOwner)
359 hwndOwner = HWND_DESKTOP;
[144]360
[551]361 DosBeep(250, 100);
[327]362
[182]363 return WinMessageBox(HWND_DESKTOP, // Parent
[616]364 hwndOwner,
[551]365 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]366 mb_type | MB_MOVEABLE);
[613]367} // showMsg
[616]368
[636]369//== Win_Error: report Win...() error using passed message string ===
[616]370
[636]371VOID Win_Error(HWND hwndErr, HWND hwndOwner,
372 PCSZ pszSrcFile, UINT uSrcLineNo,
373 PCSZ pszFmt, ...)
[616]374{
[636]375 CHAR szMsg[4096];
[616]376 va_list va;
377
[636]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);
[616]416 fputc('\n', stderr);
[636]417 fputc('\n', stderr);
[616]418 fflush(stderr);
419
[636]420 DosBeep(250, 100);
[616]421
[636]422} // Win_Error_NoMsgBox
[787]423
424#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,GetHiresTimeer)
Note: See TracBrowser for help on using the repository browser.