source: trunk/dll/errutil.c@ 1558

Last change on this file since 1558 was 1558, checked in by Steven Levine, 15 years ago

Remap API errors code that with odd oso001*.msg messages

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1
2/***********************************************************************
3
4 $Id: errutil.c 1558 2010-12-01 22:15:20Z stevenhl $
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
219 by WinGetErrorInfo */
220 PSZ pszOffset; /* Pointer to current error message returned
221 by WinGetErrorInfo */
222 PSZ psz;
223 HAB hab;
224
225 if (hwndErr == NULLHANDLE)
226 hab = (HAB)0;
227 else
228 hab = WinQueryAnchorBlock(hwndErr);
229
230 // Format callers message
231 pszBuf[cBufBytes - 1] = 0;
232 vsprintf(pszBuf, pszFmt, pva);
233
234 if (pszBuf[cBufBytes - 1]) {
235 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
236 fflush(stderr);
237 }
238
239 if (strchr(pszBuf, ' ') == NULL) {
240 strcat(pszBuf, " ");
241 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
242 }
243
244 // Append file name and line number and trailing space
245 sprintf(pszBuf + strlen(pszBuf),
246 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
247
248 // Get last PM error for the current thread
249 pErrInfoBlk = WinGetErrorInfo(hab);
250 if (!pErrInfoBlk) {
251 ERRORID id = WinGetLastError(hab);
252 psz = pszBuf + strlen(pszBuf);
253 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
254 }
255 else {
256 if (!hwndOwner)
257 hwndOwner = HWND_DESKTOP;
258 /* Find message offset in array of message offsets
259 Assume 1 message - fixme?
260 */
261 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
262 /* Address error message in array of messages and
263 append error message to source code linenumber
264 */
265 psz = pszBuf + strlen(pszBuf);
266 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
267 psz += strlen(psz);
268 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
269 psz += strlen(psz);
270 // Chop trailing mush
271 psz--;
272 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
273 *psz-- = 0;
274 if (*psz)
275 psz++;
276 strcpy(psz, "\"");
277 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
278 }
279
280} // formatWinError
281
282/**
283 * Return millisecond timer value
284 * Resolution is milliseconds, but accuracy will be less
285 * depending on systems settings
286 */
287
288ULONG GetMSecTimer(void)
289{
290 ULONG msec;
291
292 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
293 &msec, sizeof(msec));
294 if (rc) {
295 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
296 "DosQuerySysInfo");
297 msec = 0;
298 }
299 return msec;
300}
301
302//== Runtime_Error: report runtime library error using passed message string ===
303//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
304
305VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
306{
307 CHAR szMsg[4096];
308 va_list va;
309
310 // Format caller's message
311 if (!pszFmt)
312 pszFmt = PCSZ_NODATA;
313 va_start(va, pszFmt);
314 szMsg[sizeof(szMsg) - 1] = 0;
315 vsprintf(szMsg, pszFmt, va);
316 va_end(va);
317
318 if (szMsg[sizeof(szMsg) - 1]) {
319 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
320 fflush(stderr);
321 }
322
323 if (strchr(szMsg, ' ') == NULL) {
324 strcat(szMsg, " ");
325 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
326 }
327
328 sprintf(szMsg + strlen(szMsg),
329 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
330
331 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
332
333} // Runtime_Error
334
335//=== saymsg: report misc error using passed message ===
336
337APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
338{
339 CHAR szMsg[4096];
340 va_list va;
341
342 va_start(va, pszFmt);
343 szMsg[sizeof(szMsg) - 1] = 0;
344 vsprintf(szMsg, pszFmt, va);
345 va_end(va);
346
347 if (szMsg[sizeof(szMsg) - 1]) {
348 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
349 fflush(stderr);
350 }
351
352 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
353
354} // saymsg
355
356//=== showMsg: display error popup ===
357
358static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
359 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
360{
361 if (wantLog) {
362 fputs(pszMsg, stderr);
363 fputc('\n', stderr);
364 fputc('\n', stderr);
365 fflush(stderr);
366 }
367
368 if (!hwndOwner)
369 hwndOwner = HWND_DESKTOP;
370 if (!fErrorBeepOff)
371 DosBeep(250, 100);
372
373 return WinMessageBox(HWND_DESKTOP, // Parent
374 hwndOwner,
375 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
376 mb_type | MB_MOVEABLE);
377} // showMsg
378
379//== Win_Error: report Win...() error using passed message string ===
380
381VOID Win_Error(HWND hwndErr, HWND hwndOwner,
382 PCSZ pszSrcFile, UINT uSrcLineNo,
383 PCSZ pszFmt, ...)
384{
385 CHAR szMsg[4096];
386 va_list va;
387
388 // Format callers message
389 va_start(va, pszFmt);
390 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
391 va_end(va);
392
393 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
394 szMsg, TRUE);
395
396} // Win_Error
397
398/**
399 * Output PM error messsage to stderr
400 * This does to same reporting as Win_Error, but bypasses the
401 * message box popup.
402 * Use this version when the popup would hang PM.
403 */
404
405VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
406 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
407{
408 CHAR szMsg[4096];
409 va_list va;
410
411 // Format callers message
412 va_start(va, pszFmt);
413 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
414 va_end(va);
415
416 fputs(szMsg, stderr);
417 fputc('\n', stderr);
418 fputc('\n', stderr);
419 fflush(stderr);
420 if (!fErrorBeepOff)
421 DosBeep(250, 100);
422
423} // Win_Error_NoMsgBox
424
425#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.