source: trunk/dll/errutil.c@ 1686

Last change on this file since 1686 was 1686, checked in by Gregg Young, 12 years ago

GKY Improvrd readonly check on delete to allow cancel and don't ask again options; Added saymsg2 for this purpose; Fixes to snapshot file. cs 1685 contained the COMP.C changes

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