source: trunk/dll/errutil.c@ 1449

Last change on this file since 1449 was 1449, checked in by Gregg Young, 16 years ago

Fix failure of containers to update when Tree container isn't open in FM2 lite; get DosGetMessage to work in HIMEM builds (Ticket 389, 390)

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