source: trunk/dll/errutil.c@ 1450

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

Add a PCSZ srting for error messages; prevent error popup for locked text file on directory scan (scan works as expected anyway); Pass file names on stack which is in low mem for DosGetMessage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1
2/***********************************************************************
3
4 $Id: errutil.c 1450 2009-07-27 22:23:55Z 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[20], szMsgFileH[20];
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 // Format caller's message
134 va_start(va, pszFmt);
135 szMsg[sizeof(szMsg) - 1] = 0;
136 vsprintf(szMsg, pszFmt, va);
137 va_end(va);
138
139 if (szMsg[sizeof(szMsg) - 1]) {
140 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
141 fflush(stderr);
142 }
143
144 if (strchr(szMsg, ' ') == NULL) {
145 strcat(szMsg, " ");
146 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
147 }
148
149 DosErrClass(ulRC, &Class, &action, &Locus);
150
151 sprintf(szMsg + strlen(szMsg),
152 GetPString(IDS_DOSERR1TEXT),
153 pszSrcFile,
154 uSrcLineNo,
155 ulRC,
156 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
157 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
158 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
159 pszMsgStart = szMsg + strlen(szMsg) + 1;
160 strcpy(szMsgFile, "OSO001.MSG");
161 strcpy(szMsgFileH, "OSO001H.MSG");
162 // Get message leaving space for NL separator
163 if (!DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC, szMsgFile, &ulMsgLen)
164 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC,
165 szMsgFileH, &ulMsgLen)) {
166 // Got message
167 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
168 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
169 *pszMsgStart = '\"'; // Prefix message text with quote
170
171 psz = pszMsgStart + ulMsgLen; // Point at last char
172 // Chop trailing NL CR TAB
173 while (*psz &&
174 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
175 *psz-- = 0;
176 }
177 strcat(psz, "\""); // Append trailing quote
178
179 // Convert CR and NL combos to single space
180 psz = pszMsgStart;
181 while (*psz) {
182 if (*psz == '\n' || *psz == '\r') {
183 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
184 memmove(psz, psz + 1, strlen(psz));
185 *psz = ' ';
186 }
187 else
188 psz++;
189 }
190 }
191
192 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
193 szMsg, TRUE);
194
195} // Dos_Error
196
197/**
198 * Format last PM error into passed buffer
199 */
200
201static VOID formatWinError(PSZ pszBuf, UINT cBufBytes,
202 HWND hwndErr, HWND hwndOwner,
203 PCSZ pszSrcFile, UINT uSrcLineNo,
204 PCSZ pszFmt, va_list pva)
205{
206 PERRINFO pErrInfoBlk; /* Pointer to ERRINFO structure filled
207 by WinGetErrorInfo */
208 PSZ pszOffset; /* Pointer to current error message returned
209 by WinGetErrorInfo */
210 PSZ psz;
211 HAB hab;
212
213 if (hwndErr == NULLHANDLE)
214 hab = (HAB)0;
215 else
216 hab = WinQueryAnchorBlock(hwndErr);
217
218 // Format callers message
219 pszBuf[cBufBytes - 1] = 0;
220 vsprintf(pszBuf, pszFmt, pva);
221
222 if (pszBuf[cBufBytes - 1]) {
223 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
224 fflush(stderr);
225 }
226
227 if (strchr(pszBuf, ' ') == NULL) {
228 strcat(pszBuf, " ");
229 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
230 }
231
232 // Append file name and line number and trailing space
233 sprintf(pszBuf + strlen(pszBuf),
234 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
235
236 // Get last PM error for the current thread
237 pErrInfoBlk = WinGetErrorInfo(hab);
238 if (!pErrInfoBlk) {
239 ERRORID id = WinGetLastError(hab);
240 psz = pszBuf + strlen(pszBuf);
241 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
242 }
243 else {
244 if (!hwndOwner)
245 hwndOwner = HWND_DESKTOP;
246 /* Find message offset in array of message offsets
247 Assume 1 message - fixme?
248 */
249 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
250 /* Address error message in array of messages and
251 append error message to source code linenumber
252 */
253 psz = pszBuf + strlen(pszBuf);
254 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
255 psz += strlen(psz);
256 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
257 psz += strlen(psz);
258 // Chop trailing mush
259 psz--;
260 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
261 *psz-- = 0;
262 if (*psz)
263 psz++;
264 strcpy(psz, "\"");
265 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
266 }
267
268} // formatWinError
269
270/**
271 * Return millisecond timer value
272 * Resolution is milliseconds, but accuracy will be less
273 * depending on systems settings
274 */
275
276ULONG GetMSecTimer(void)
277{
278 ULONG msec;
279
280 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
281 &msec, sizeof(msec));
282 if (rc) {
283 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
284 "DosQuerySysInfo");
285 msec = 0;
286 }
287 return msec;
288}
289
290//== Runtime_Error: report runtime library error using passed message string ===
291//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
292
293VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
294{
295 CHAR szMsg[4096];
296 va_list va;
297
298 // Format caller's message
299 if (!pszFmt)
300 pszFmt = PCSZ_NODATA;
301 va_start(va, pszFmt);
302 szMsg[sizeof(szMsg) - 1] = 0;
303 vsprintf(szMsg, pszFmt, va);
304 va_end(va);
305
306 if (szMsg[sizeof(szMsg) - 1]) {
307 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
308 fflush(stderr);
309 }
310
311 if (strchr(szMsg, ' ') == NULL) {
312 strcat(szMsg, " ");
313 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
314 }
315
316 sprintf(szMsg + strlen(szMsg),
317 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
318
319 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
320
321} // Runtime_Error
322
323//=== saymsg: report misc error using passed message ===
324
325APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
326{
327 CHAR szMsg[4096];
328 va_list va;
329
330 va_start(va, pszFmt);
331 szMsg[sizeof(szMsg) - 1] = 0;
332 vsprintf(szMsg, pszFmt, va);
333 va_end(va);
334
335 if (szMsg[sizeof(szMsg) - 1]) {
336 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
337 fflush(stderr);
338 }
339
340 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
341
342} // saymsg
343
344//=== showMsg: display error popup ===
345
346static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
347 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
348{
349 if (wantLog) {
350 fputs(pszMsg, stderr);
351 fputc('\n', stderr);
352 fputc('\n', stderr);
353 fflush(stderr);
354 }
355
356 if (!hwndOwner)
357 hwndOwner = HWND_DESKTOP;
358 if (!fErrorBeepOff)
359 DosBeep(250, 100);
360
361 return WinMessageBox(HWND_DESKTOP, // Parent
362 hwndOwner,
363 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
364 mb_type | MB_MOVEABLE);
365} // showMsg
366
367//== Win_Error: report Win...() error using passed message string ===
368
369VOID Win_Error(HWND hwndErr, HWND hwndOwner,
370 PCSZ pszSrcFile, UINT uSrcLineNo,
371 PCSZ pszFmt, ...)
372{
373 CHAR szMsg[4096];
374 va_list va;
375
376 // Format callers message
377 va_start(va, pszFmt);
378 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
379 va_end(va);
380
381 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
382 szMsg, TRUE);
383
384} // Win_Error
385
386/**
387 * Output PM error messsage to stderr
388 * This does to same reporting as Win_Error, but bypasses the
389 * message box popup.
390 * Use this version when the popup would hang PM.
391 */
392
393VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
394 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
395{
396 CHAR szMsg[4096];
397 va_list va;
398
399 // Format callers message
400 va_start(va, pszFmt);
401 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
402 va_end(va);
403
404 fputs(szMsg, stderr);
405 fputc('\n', stderr);
406 fputc('\n', stderr);
407 fflush(stderr);
408 if (!fErrorBeepOff)
409 DosBeep(250, 100);
410
411} // Win_Error_NoMsgBox
412
413#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.