source: trunk/dll/errutil.c@ 1395

Last change on this file since 1395 was 1395, checked in by Gregg Young, 17 years ago

Allow user to turn off alert and/or error beeps in settings notebook. Ticket 341 Move repeated strings to PCSZs. Ticket 6 Add *DateFormat functions to format dates based on locale Ticket 28 Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error Ticket 6

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