source: trunk/dll/errutil.c@ 907

Last change on this file since 907 was 907, checked in by Steven Levine, 18 years ago

Avoid out of memory traps in Compare Directories
Rework Compare Directories progress display for 2 second update rate
Start refactoring to reduce dependence on fm3dll.h
Add timer services (IsITimerExpired etc.)

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