source: trunk/dll/error.c@ 904

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

Correct message spacing

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