source: trunk/dll/errutil.c@ 1673

Last change on this file since 1673 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

  • 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 1673 2012-12-30 18:51:01Z gyoung $
5
6 Error reporting
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2004, 2010 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 08 Mar 09 GKY Remove Dos_Error2 (unused) and Runtime_Error2 (no advantage over using Runtime_Error)
35 23 Jul 09 GKY Add low mem buffers for the msg file name so DosGetMessage
36 works in HIMEM builds
37 01 Dec 10 SHL Dos_Error - remap API errors code that with odd oso001*.msg messages
38
39***********************************************************************/
40
41#include <stdio.h>
42#include <string.h>
43#include <stdarg.h>
44
45#define INCL_DOS
46#define INCL_WIN
47#define INCL_DOSERRORS
48#define INCL_DOSPROCESS // PPIB PTIB
49#define INCL_LONGLONG
50
51#include "errutil.h"
52#include "strutil.h" // GetPString
53#include "fm3str.h"
54#include "notebook.h" // fErrorBeepOff
55#include "init.h" // Data declares
56
57#pragma data_seg(DATA1)
58
59static PSZ pszSrcFile = __FILE__;
60
61static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
62 PCSZ pszSrcFile, UINT uSrcLineNo,
63 PCSZ pszFmt, va_list pva);
64
65static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
66
67//=== DbgMsg: output debug message stderr ===
68
69VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
70{
71 PIB *ppib;
72 TIB *ptib;
73 ULONG ultid;
74 APIRET apiret;
75 va_list va;
76
77#if 1 // fixme to be selectable
78
79 static ULONG ul1stMSec;
80 // static ULONG ulLastMSec;
81
82 ULONG msec = GetMSecTimer();
83 ULONG delta;
84
85 if (!ul1stMSec) {
86 ul1stMSec = msec;
87 // ulLastMSec = msec; // Avoid big delta 1st time
88 }
89
90 delta = msec - ul1stMSec;
91 // ulLastMSec = msec;
92 fprintf(stderr, "%03lu.%03lu ", delta / 1000, delta % 1000);
93
94#endif
95
96 apiret = DosGetInfoBlocks(&ptib, &ppib);
97 if (apiret)
98 ultid = 0;
99 else
100 ultid = ptib->tib_ptib2->tib2_ultid;
101
102 // OK for source file name to be null
103 fprintf(stderr, "%s %u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
104 // If format null want just file and line
105 if (pszFmt) {
106 fputc(' ', stderr);
107 va_start(va, pszFmt);
108 vfprintf(stderr, pszFmt, va);
109 va_end(va);
110 }
111 fputc('\n', stderr);
112 fflush(stderr);
113
114} // DbgMsg
115
116//== Dos_Error: report Dos...() error using passed message string ===
117
118// 2010-12-01 SHL fixme for ULONG to be APIRET
119
120INT Dos_Error(ULONG mb_type, ULONG apiret, HWND hwndOwner,
121 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
122{
123 CHAR szMsg[4096];
124 CHAR szMsgFile[20], szMsgFileH[20];
125 ULONG Class; // Error class
126 ULONG action; // Error action
127 ULONG Locus; // Error location
128 ULONG ulMsgLen;
129 APIRET mapped_apiret;
130 CHAR *pszMsgStart;
131 CHAR *psz;
132 va_list va;
133
134 if (!apiret)
135 return MBID_ENTER; // Should not have been called
136
137 // Format caller's message
138 va_start(va, pszFmt);
139 szMsg[sizeof(szMsg) - 1] = 0;
140 vsprintf(szMsg, pszFmt, va);
141 va_end(va);
142
143 if (szMsg[sizeof(szMsg) - 1]) {
144 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
145 fflush(stderr);
146 }
147
148 if (strchr(szMsg, ' ') == NULL) {
149 strcat(szMsg, " ");
150 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
151 }
152
153 DosErrClass(apiret, &Class, &action, &Locus);
154
155 sprintf(szMsg + strlen(szMsg),
156 GetPString(IDS_DOSERR1TEXT),
157 pszSrcFile,
158 uSrcLineNo,
159 apiret,
160 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
161 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
162 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
163 pszMsgStart = szMsg + strlen(szMsg) + 1;
164 strcpy(szMsgFile, "OSO001.MSG");
165 strcpy(szMsgFileH, "OSO001H.MSG");
166 // Get message leaving space for NL separator
167 // 2010-12-01 SHL Handle cases where message file message does not make sense relative to API error
168 switch (apiret) {
169 case ERROR_TIMEOUT:
170 mapped_apiret = ERROR_SEM_TIMEOUT; // Assume semaphore timeout
171 break;
172 default:
173 mapped_apiret = apiret;
174 }
175 if (!DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, mapped_apiret, szMsgFile, &ulMsgLen)
176 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, mapped_apiret,
177 szMsgFileH, &ulMsgLen)) {
178 // Got message
179 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
180 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
181 *pszMsgStart = '\"'; // Prefix message text with quote
182
183 psz = pszMsgStart + ulMsgLen; // Point at last char
184 // Chop trailing NL CR TAB
185 while (*psz &&
186 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
187 *psz-- = 0;
188 }
189 strcat(psz, "\""); // Append trailing quote
190
191 // Convert CR and NL combos to single space
192 psz = pszMsgStart;
193 while (*psz) {
194 if (*psz == '\n' || *psz == '\r') {
195 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
196 memmove(psz, psz + 1, strlen(psz));
197 *psz = ' ';
198 }
199 else
200 psz++;
201 }
202 }
203
204 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
205 szMsg, TRUE);
206
207} // Dos_Error
208
209/**
210 * Format last PM error into passed buffer
211 */
212
213static VOID formatWinError(PSZ pszBuf, UINT cBufBytes,
214 HWND hwndErr, HWND hwndOwner,
215 PCSZ pszSrcFile, UINT uSrcLineNo,
216 PCSZ pszFmt, va_list pva)
217{
218 PERRINFO pErrInfoBlk; // Pointer to ERRINFO structure filled by WinGetErrorInfo
219 PSZ pszOffset; // Pointer to current error message returned by WinGetErrorInfo
220 PSZ psz;
221 HAB hab;
222
223 if (hwndErr == NULLHANDLE)
224 hab = (HAB)0;
225 else
226 hab = WinQueryAnchorBlock(hwndErr);
227
228 // Format callers message
229 pszBuf[cBufBytes - 1] = 0;
230 vsprintf(pszBuf, pszFmt, pva);
231
232 if (pszBuf[cBufBytes - 1]) {
233 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
234 fflush(stderr);
235 }
236
237 if (strchr(pszBuf, ' ') == NULL) {
238 strcat(pszBuf, " ");
239 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
240 }
241
242 // Append file name and line number and trailing space
243 sprintf(pszBuf + strlen(pszBuf),
244 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
245
246 // Get last PM error for the current thread
247 pErrInfoBlk = WinGetErrorInfo(hab);
248 if (!pErrInfoBlk) {
249 ERRORID id = WinGetLastError(hab);
250 psz = pszBuf + strlen(pszBuf);
251 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
252 }
253 else {
254 if (!hwndOwner)
255 hwndOwner = HWND_DESKTOP;
256 // Find message offset in array of message offsets Assume 1 message - fixme?
257 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
258 // Address error message in array of messages and append error message to source code linenumber
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//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
298
299VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
300{
301 CHAR szMsg[4096];
302 va_list va;
303
304 // Format caller's message
305 if (!pszFmt)
306 pszFmt = PCSZ_NODATA;
307 va_start(va, pszFmt);
308 szMsg[sizeof(szMsg) - 1] = 0;
309 vsprintf(szMsg, pszFmt, va);
310 va_end(va);
311
312 if (szMsg[sizeof(szMsg) - 1]) {
313 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
314 fflush(stderr);
315 }
316
317 if (strchr(szMsg, ' ') == NULL) {
318 strcat(szMsg, " ");
319 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
320 }
321
322 sprintf(szMsg + strlen(szMsg),
323 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
324
325 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
326
327} // Runtime_Error
328
329//=== saymsg: report misc error using passed message ===
330
331APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
332{
333 CHAR szMsg[4096];
334 va_list va;
335
336 va_start(va, pszFmt);
337 szMsg[sizeof(szMsg) - 1] = 0;
338 vsprintf(szMsg, pszFmt, va);
339 va_end(va);
340
341 if (szMsg[sizeof(szMsg) - 1]) {
342 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
343 fflush(stderr);
344 }
345
346 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
347
348} // saymsg
349
350//=== showMsg: display error popup ===
351
352static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
353 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
354{
355 if (wantLog) {
356 fputs(pszMsg, stderr);
357 fputc('\n', stderr);
358 fputc('\n', stderr);
359 fflush(stderr);
360 }
361
362 if (!hwndOwner)
363 hwndOwner = HWND_DESKTOP;
364 if (!fErrorBeepOff)
365 DosBeep(250, 100);
366
367 return WinMessageBox(HWND_DESKTOP, // Parent
368 hwndOwner,
369 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
370 mb_type | MB_MOVEABLE);
371} // showMsg
372
373//== Win_Error: report Win...() error using passed message string ===
374
375VOID Win_Error(HWND hwndErr, HWND hwndOwner,
376 PCSZ pszSrcFile, UINT uSrcLineNo,
377 PCSZ pszFmt, ...)
378{
379 CHAR szMsg[4096];
380 va_list va;
381
382 // Format callers message
383 va_start(va, pszFmt);
384 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
385 va_end(va);
386
387 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
388 szMsg, TRUE);
389
390} // Win_Error
391
392/**
393 * Output PM error messsage to stderr
394 * This does to same reporting as Win_Error, but bypasses the
395 * message box popup.
396 * Use this version when the popup would hang PM.
397 */
398
399VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
400 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
401{
402 CHAR szMsg[4096];
403 va_list va;
404
405 // Format callers message
406 va_start(va, pszFmt);
407 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
408 va_end(va);
409
410 fputs(szMsg, stderr);
411 fputc('\n', stderr);
412 fputc('\n', stderr);
413 fflush(stderr);
414 if (!fErrorBeepOff)
415 DosBeep(250, 100);
416
417} // Win_Error_NoMsgBox
418
419#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.