source: trunk/dll/errutil.c@ 1673

Last change on this file since 1673 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

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