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
RevLine 
[121]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
[1558]9 Copyright (c) 2004, 2010 Steven H. Levine
[121]10
[137]11 12 Aug 04 SHL Comments
12 23 May 05 SHL Move saymsg here
[144]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
[182]16 27 May 05 SHL Rework to use common showMsg
[258]17 14 Aug 05 SHL showMsg: suppress write to stdout if not error message
[327]18 13 Jul 06 SHL Add Runtime_Error
19 22 Jul 06 SHL Optimize calling sequences
[383]20 26 Jul 06 SHL Add ..._Error2
[452]21 16 Aug 06 SHL Tweak message formatting
[552]22 07 Jan 07 GKY Move error strings etc. to string file
[613]23 18 Apr 07 SHL showMsg: correct selective logging checks
[616]24 19 Apr 07 SHL Add DbgMsg
25 20 Apr 07 SHL Correct IDS_GENERR1TEXT formatting
[636]26 23 Apr 07 SHL Add Win_Error_NoMsgBox. Rework others
[787]27 14 Aug 07 SHL Add GetMSecTimer
28 14 Aug 07 SHL Use GetMSecTimer in DbgMsg
[907]29 05 Jan 08 SHL Renamed from error.c to match errutil.h
[1373]30 18 Dec 08 SHL Show thread id in DbgMsg
[1395]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.
[1402]34 08 Mar 09 GKY Remove Dos_Error2 (unused) and Runtime_Error2 (no advantage over using Runtime_Error)
[1449]35 23 Jul 09 GKY Add low mem buffers for the msg file name so DosGetMessage
[1558]36 works in HIMEM builds
37 01 Dec 10 SHL Dos_Error - remap API errors code that with odd oso001*.msg messages
[1686]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
[121]40
41***********************************************************************/
42
[907]43#include <stdio.h>
44#include <string.h>
45#include <stdarg.h>
[1686]46#include <stdlib.h>
[907]47
[2]48#define INCL_DOS
[1373]49#define INCL_WIN
[2]50#define INCL_DOSERRORS
[1373]51#define INCL_DOSPROCESS // PPIB PTIB
[1395]52#define INCL_LONGLONG
[2]53
[907]54#include "errutil.h"
55#include "strutil.h" // GetPString
[2]56#include "fm3str.h"
[1558]57#include "notebook.h" // fErrorBeepOff
58#include "init.h" // Data declares
[1686]59#include "wrappers.h" // xmallocz
[2]60
61#pragma data_seg(DATA1)
62
[787]63static PSZ pszSrcFile = __FILE__;
64
[636]65static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
66 PCSZ pszSrcFile, UINT uSrcLineNo,
67 PCSZ pszFmt, va_list pva);
68
[613]69static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
[2]70
[636]71//=== DbgMsg: output debug message stderr ===
[144]72
[636]73VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]74{
[1373]75 PIB *ppib;
76 TIB *ptib;
77 ULONG ultid;
78 APIRET apiret;
[144]79 va_list va;
[2]80
[787]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;
[1558]91 // ulLastMSec = msec; // Avoid big delta 1st time
[787]92 }
93
94 delta = msec - ul1stMSec;
95 // ulLastMSec = msec;
96 fprintf(stderr, "%03lu.%03lu ", delta / 1000, delta % 1000);
97
98#endif
99
[1373]100 apiret = DosGetInfoBlocks(&ptib, &ppib);
101 if (apiret)
102 ultid = 0;
103 else
104 ultid = ptib->tib_ptib2->tib2_ultid;
105
[636]106 // OK for source file name to be null
[1373]107 fprintf(stderr, "%s %u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
[636]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);
[613]114 }
[636]115 fputc('\n', stderr);
116 fflush(stderr);
[613]117
[636]118} // DbgMsg
[327]119
[452]120//== Dos_Error: report Dos...() error using passed message string ===
[144]121
[1558]122// 2010-12-01 SHL fixme for ULONG to be APIRET
123
124INT Dos_Error(ULONG mb_type, ULONG apiret, HWND hwndOwner,
[636]125 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]126{
[182]127 CHAR szMsg[4096];
[1450]128 CHAR szMsgFile[20], szMsgFileH[20];
[636]129 ULONG Class; // Error class
130 ULONG action; // Error action
[1558]131 ULONG Locus; // Error location
[144]132 ULONG ulMsgLen;
[1558]133 APIRET mapped_apiret;
[144]134 CHAR *pszMsgStart;
135 CHAR *psz;
136 va_list va;
[2]137
[1558]138 if (!apiret)
[144]139 return MBID_ENTER; // Should not have been called
[121]140
[144]141 // Format caller's message
142 va_start(va, pszFmt);
[613]143 szMsg[sizeof(szMsg) - 1] = 0;
[182]144 vsprintf(szMsg, pszFmt, va);
[144]145 va_end(va);
[121]146
[613]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
[1395]152 if (strchr(szMsg, ' ') == NULL) {
153 strcat(szMsg, " ");
[1558]154 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]155 }
[327]156
[1558]157 DosErrClass(apiret, &Class, &action, &Locus);
[144]158
[182]159 sprintf(szMsg + strlen(szMsg),
[144]160 GetPString(IDS_DOSERR1TEXT),
[636]161 pszSrcFile,
162 uSrcLineNo,
[1558]163 apiret,
[144]164 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
165 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
[1558]166 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
[182]167 pszMsgStart = szMsg + strlen(szMsg) + 1;
[1449]168 strcpy(szMsgFile, "OSO001.MSG");
169 strcpy(szMsgFileH, "OSO001H.MSG");
[144]170 // Get message leaving space for NL separator
[1558]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)) {
[144]182 // Got message
183 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
[182]184 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
[144]185 *pszMsgStart = '\"'; // Prefix message text with quote
[182]186
[144]187 psz = pszMsgStart + ulMsgLen; // Point at last char
188 // Chop trailing NL CR TAB
189 while (*psz &&
[551]190 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
[144]191 *psz-- = 0;
192 }
193 strcat(psz, "\""); // Append trailing quote
194
195 // Convert CR and NL combos to single space
196 psz = pszMsgStart;
[551]197 while (*psz) {
198 if (*psz == '\n' || *psz == '\r') {
[144]199 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
200 memmove(psz, psz + 1, strlen(psz));
201 *psz = ' ';
[2]202 }
[144]203 else
204 psz++;
[2]205 }
206 }
[137]207
[613]208 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
209 szMsg, TRUE);
[137]210
[636]211} // Dos_Error
[137]212
[636]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{
[1673]222 PERRINFO pErrInfoBlk; // Pointer to ERRINFO structure filled by WinGetErrorInfo
223 PSZ pszOffset; // Pointer to current error message returned by WinGetErrorInfo
[636]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
[1395]241 if (strchr(pszBuf, ' ') == NULL) {
242 strcat(pszBuf, " ");
[1558]243 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]244 }
[636]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) {
[907]253 ERRORID id = WinGetLastError(hab);
[636]254 psz = pszBuf + strlen(pszBuf);
[904]255 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]256 }
257 else {
258 if (!hwndOwner)
259 hwndOwner = HWND_DESKTOP;
[1673]260 // Find message offset in array of message offsets Assume 1 message - fixme?
[636]261 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
[1673]262 // Address error message in array of messages and append error message to source code linenumber
[636]263 psz = pszBuf + strlen(pszBuf);
[904]264 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]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
[787]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
[452]300//== Runtime_Error: report runtime library error using passed message string ===
[1398]301//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
[327]302
[551]303VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]304{
305 CHAR szMsg[4096];
306 va_list va;
307
308 // Format caller's message
[1398]309 if (!pszFmt)
310 pszFmt = PCSZ_NODATA;
[327]311 va_start(va, pszFmt);
[613]312 szMsg[sizeof(szMsg) - 1] = 0;
[327]313 vsprintf(szMsg, pszFmt, va);
314 va_end(va);
315
[613]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
[1395]321 if (strchr(szMsg, ' ') == NULL) {
322 strcat(szMsg, " ");
[1558]323 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]324 }
[327]325
326 sprintf(szMsg + strlen(szMsg),
[613]327 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]328
[1395]329 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
[327]330
[636]331} // Runtime_Error
[327]332
[452]333//=== saymsg: report misc error using passed message ===
[144]334
[551]335APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]336{
[182]337 CHAR szMsg[4096];
[144]338 va_list va;
[137]339
[144]340 va_start(va, pszFmt);
[613]341 szMsg[sizeof(szMsg) - 1] = 0;
[182]342 vsprintf(szMsg, pszFmt, va);
[144]343 va_end(va);
344
[613]345 if (szMsg[sizeof(szMsg) - 1]) {
346 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
347 fflush(stderr);
348 }
[452]349
[613]350 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
351
[636]352} // saymsg
[182]353
[1686]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
[452]405//=== showMsg: display error popup ===
[182]406
[636]407static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
408 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]409{
[613]410 if (wantLog) {
[258]411 fputs(pszMsg, stderr);
412 fputc('\n', stderr);
[614]413 fputc('\n', stderr);
[258]414 fflush(stderr);
415 }
416
[616]417 if (!hwndOwner)
418 hwndOwner = HWND_DESKTOP;
[1395]419 if (!fErrorBeepOff)
420 DosBeep(250, 100);
[144]421
[182]422 return WinMessageBox(HWND_DESKTOP, // Parent
[616]423 hwndOwner,
[551]424 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]425 mb_type | MB_MOVEABLE);
[613]426} // showMsg
[616]427
[636]428//== Win_Error: report Win...() error using passed message string ===
[616]429
[636]430VOID Win_Error(HWND hwndErr, HWND hwndOwner,
431 PCSZ pszSrcFile, UINT uSrcLineNo,
432 PCSZ pszFmt, ...)
[616]433{
[636]434 CHAR szMsg[4096];
[616]435 va_list va;
436
[636]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);
[616]466 fputc('\n', stderr);
[636]467 fputc('\n', stderr);
[616]468 fflush(stderr);
[1395]469 if (!fErrorBeepOff)
470 DosBeep(250, 100);
[616]471
[636]472} // Win_Error_NoMsgBox
[787]473
[1402]474#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.