source: trunk/dll/errutil.c@ 1450

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

Add a PCSZ srting for error messages; prevent error popup for locked text file on directory scan (scan works as expected anyway); Pass file names on stack which is in low mem for DosGetMessage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
RevLine 
[121]1
2/***********************************************************************
3
4 $Id: errutil.c 1450 2009-07-27 22:23:55Z 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];
[1450]121 CHAR szMsgFile[20], szMsgFileH[20];
[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
[144]133 // Format caller's message
134 va_start(va, pszFmt);
[613]135 szMsg[sizeof(szMsg) - 1] = 0;
[182]136 vsprintf(szMsg, pszFmt, va);
[144]137 va_end(va);
[121]138
[613]139 if (szMsg[sizeof(szMsg) - 1]) {
140 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
141 fflush(stderr);
142 }
143
[1395]144 if (strchr(szMsg, ' ') == NULL) {
145 strcat(szMsg, " ");
146 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
147 }
[327]148
[144]149 DosErrClass(ulRC, &Class, &action, &Locus);
150
[182]151 sprintf(szMsg + strlen(szMsg),
[144]152 GetPString(IDS_DOSERR1TEXT),
[636]153 pszSrcFile,
154 uSrcLineNo,
[144]155 ulRC,
156 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
157 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
[1447]158 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
[182]159 pszMsgStart = szMsg + strlen(szMsg) + 1;
[1449]160 strcpy(szMsgFile, "OSO001.MSG");
161 strcpy(szMsgFileH, "OSO001H.MSG");
[144]162 // Get message leaving space for NL separator
[1449]163 if (!DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC, szMsgFile, &ulMsgLen)
[551]164 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC,
[1449]165 szMsgFileH, &ulMsgLen)) {
[144]166 // Got message
167 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
[182]168 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
[144]169 *pszMsgStart = '\"'; // Prefix message text with quote
[182]170
[144]171 psz = pszMsgStart + ulMsgLen; // Point at last char
172 // Chop trailing NL CR TAB
173 while (*psz &&
[551]174 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
[144]175 *psz-- = 0;
176 }
177 strcat(psz, "\""); // Append trailing quote
178
179 // Convert CR and NL combos to single space
180 psz = pszMsgStart;
[551]181 while (*psz) {
182 if (*psz == '\n' || *psz == '\r') {
[144]183 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
184 memmove(psz, psz + 1, strlen(psz));
185 *psz = ' ';
[2]186 }
[144]187 else
188 psz++;
[2]189 }
190 }
[137]191
[613]192 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
193 szMsg, TRUE);
[137]194
[636]195} // Dos_Error
[137]196
[636]197/**
198 * Format last PM error into passed buffer
199 */
200
201static VOID formatWinError(PSZ pszBuf, UINT cBufBytes,
202 HWND hwndErr, HWND hwndOwner,
203 PCSZ pszSrcFile, UINT uSrcLineNo,
204 PCSZ pszFmt, va_list pva)
205{
206 PERRINFO pErrInfoBlk; /* Pointer to ERRINFO structure filled
207 by WinGetErrorInfo */
208 PSZ pszOffset; /* Pointer to current error message returned
209 by WinGetErrorInfo */
210 PSZ psz;
211 HAB hab;
212
213 if (hwndErr == NULLHANDLE)
214 hab = (HAB)0;
215 else
216 hab = WinQueryAnchorBlock(hwndErr);
217
218 // Format callers message
219 pszBuf[cBufBytes - 1] = 0;
220 vsprintf(pszBuf, pszFmt, pva);
221
222 if (pszBuf[cBufBytes - 1]) {
223 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
224 fflush(stderr);
225 }
226
[1395]227 if (strchr(pszBuf, ' ') == NULL) {
228 strcat(pszBuf, " ");
229 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
230 }
[636]231
232 // Append file name and line number and trailing space
233 sprintf(pszBuf + strlen(pszBuf),
234 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
235
236 // Get last PM error for the current thread
237 pErrInfoBlk = WinGetErrorInfo(hab);
238 if (!pErrInfoBlk) {
[907]239 ERRORID id = WinGetLastError(hab);
[636]240 psz = pszBuf + strlen(pszBuf);
[904]241 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]242 }
243 else {
244 if (!hwndOwner)
245 hwndOwner = HWND_DESKTOP;
246 /* Find message offset in array of message offsets
247 Assume 1 message - fixme?
248 */
249 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
250 /* Address error message in array of messages and
251 append error message to source code linenumber
252 */
253 psz = pszBuf + strlen(pszBuf);
[904]254 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]255 psz += strlen(psz);
256 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
257 psz += strlen(psz);
258 // Chop trailing mush
259 psz--;
260 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
261 *psz-- = 0;
262 if (*psz)
263 psz++;
264 strcpy(psz, "\"");
265 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
266 }
267
268} // formatWinError
269
[787]270/**
271 * Return millisecond timer value
272 * Resolution is milliseconds, but accuracy will be less
273 * depending on systems settings
274 */
275
276ULONG GetMSecTimer(void)
277{
278 ULONG msec;
279
280 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
281 &msec, sizeof(msec));
282 if (rc) {
283 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
284 "DosQuerySysInfo");
285 msec = 0;
286 }
287 return msec;
288}
289
[452]290//== Runtime_Error: report runtime library error using passed message string ===
[1398]291//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
[327]292
[551]293VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]294{
295 CHAR szMsg[4096];
296 va_list va;
297
298 // Format caller's message
[1398]299 if (!pszFmt)
300 pszFmt = PCSZ_NODATA;
[327]301 va_start(va, pszFmt);
[613]302 szMsg[sizeof(szMsg) - 1] = 0;
[327]303 vsprintf(szMsg, pszFmt, va);
304 va_end(va);
305
[613]306 if (szMsg[sizeof(szMsg) - 1]) {
307 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
308 fflush(stderr);
309 }
310
[1395]311 if (strchr(szMsg, ' ') == NULL) {
312 strcat(szMsg, " ");
313 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
314 }
[327]315
316 sprintf(szMsg + strlen(szMsg),
[613]317 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]318
[1395]319 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
[327]320
[636]321} // Runtime_Error
[327]322
[452]323//=== saymsg: report misc error using passed message ===
[144]324
[551]325APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]326{
[182]327 CHAR szMsg[4096];
[144]328 va_list va;
[137]329
[144]330 va_start(va, pszFmt);
[613]331 szMsg[sizeof(szMsg) - 1] = 0;
[182]332 vsprintf(szMsg, pszFmt, va);
[144]333 va_end(va);
334
[613]335 if (szMsg[sizeof(szMsg) - 1]) {
336 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
337 fflush(stderr);
338 }
[452]339
[613]340 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
341
[636]342} // saymsg
[182]343
[452]344//=== showMsg: display error popup ===
[182]345
[636]346static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
347 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]348{
[613]349 if (wantLog) {
[258]350 fputs(pszMsg, stderr);
351 fputc('\n', stderr);
[614]352 fputc('\n', stderr);
[258]353 fflush(stderr);
354 }
355
[616]356 if (!hwndOwner)
357 hwndOwner = HWND_DESKTOP;
[1395]358 if (!fErrorBeepOff)
359 DosBeep(250, 100);
[144]360
[182]361 return WinMessageBox(HWND_DESKTOP, // Parent
[616]362 hwndOwner,
[551]363 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]364 mb_type | MB_MOVEABLE);
[613]365} // showMsg
[616]366
[636]367//== Win_Error: report Win...() error using passed message string ===
[616]368
[636]369VOID Win_Error(HWND hwndErr, HWND hwndOwner,
370 PCSZ pszSrcFile, UINT uSrcLineNo,
371 PCSZ pszFmt, ...)
[616]372{
[636]373 CHAR szMsg[4096];
[616]374 va_list va;
375
[636]376 // Format callers message
377 va_start(va, pszFmt);
378 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
379 va_end(va);
380
381 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
382 szMsg, TRUE);
383
384} // Win_Error
385
386/**
387 * Output PM error messsage to stderr
388 * This does to same reporting as Win_Error, but bypasses the
389 * message box popup.
390 * Use this version when the popup would hang PM.
391 */
392
393VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
394 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
395{
396 CHAR szMsg[4096];
397 va_list va;
398
399 // Format callers message
400 va_start(va, pszFmt);
401 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
402 va_end(va);
403
404 fputs(szMsg, stderr);
[616]405 fputc('\n', stderr);
[636]406 fputc('\n', stderr);
[616]407 fflush(stderr);
[1395]408 if (!fErrorBeepOff)
409 DosBeep(250, 100);
[616]410
[636]411} // Win_Error_NoMsgBox
[787]412
[1402]413#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.