source: trunk/dll/errutil.c@ 1449

Last change on this file since 1449 was 1449, checked in by Gregg Young, 16 years ago

Fix failure of containers to update when Tree container isn't open in FM2 lite; get DosGetMessage to work in HIMEM builds (Ticket 389, 390)

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