source: trunk/dll/errutil.c@ 1558

Last change on this file since 1558 was 1558, checked in by Steven Levine, 15 years ago

Remap API errors code that with odd oso001*.msg messages

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
RevLine 
[121]1
2/***********************************************************************
3
4 $Id: errutil.c 1558 2010-12-01 22:15:20Z stevenhl $
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{
218 PERRINFO pErrInfoBlk; /* Pointer to ERRINFO structure filled
219 by WinGetErrorInfo */
220 PSZ pszOffset; /* Pointer to current error message returned
221 by WinGetErrorInfo */
222 PSZ psz;
223 HAB hab;
224
225 if (hwndErr == NULLHANDLE)
226 hab = (HAB)0;
227 else
228 hab = WinQueryAnchorBlock(hwndErr);
229
230 // Format callers message
231 pszBuf[cBufBytes - 1] = 0;
232 vsprintf(pszBuf, pszFmt, pva);
233
234 if (pszBuf[cBufBytes - 1]) {
235 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n", strlen(pszBuf) + 1);
236 fflush(stderr);
237 }
238
[1395]239 if (strchr(pszBuf, ' ') == NULL) {
240 strcat(pszBuf, " ");
[1558]241 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]242 }
[636]243
244 // Append file name and line number and trailing space
245 sprintf(pszBuf + strlen(pszBuf),
246 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
247
248 // Get last PM error for the current thread
249 pErrInfoBlk = WinGetErrorInfo(hab);
250 if (!pErrInfoBlk) {
[907]251 ERRORID id = WinGetLastError(hab);
[636]252 psz = pszBuf + strlen(pszBuf);
[904]253 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]254 }
255 else {
256 if (!hwndOwner)
257 hwndOwner = HWND_DESKTOP;
258 /* Find message offset in array of message offsets
259 Assume 1 message - fixme?
260 */
261 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
262 /* Address error message in array of messages and
263 append error message to source code linenumber
264 */
265 psz = pszBuf + strlen(pszBuf);
[904]266 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]267 psz += strlen(psz);
268 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
269 psz += strlen(psz);
270 // Chop trailing mush
271 psz--;
272 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
273 *psz-- = 0;
274 if (*psz)
275 psz++;
276 strcpy(psz, "\"");
277 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
278 }
279
280} // formatWinError
281
[787]282/**
283 * Return millisecond timer value
284 * Resolution is milliseconds, but accuracy will be less
285 * depending on systems settings
286 */
287
288ULONG GetMSecTimer(void)
289{
290 ULONG msec;
291
292 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
293 &msec, sizeof(msec));
294 if (rc) {
295 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
296 "DosQuerySysInfo");
297 msec = 0;
298 }
299 return msec;
300}
301
[452]302//== Runtime_Error: report runtime library error using passed message string ===
[1398]303//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
[327]304
[551]305VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]306{
307 CHAR szMsg[4096];
308 va_list va;
309
310 // Format caller's message
[1398]311 if (!pszFmt)
312 pszFmt = PCSZ_NODATA;
[327]313 va_start(va, pszFmt);
[613]314 szMsg[sizeof(szMsg) - 1] = 0;
[327]315 vsprintf(szMsg, pszFmt, va);
316 va_end(va);
317
[613]318 if (szMsg[sizeof(szMsg) - 1]) {
319 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
320 fflush(stderr);
321 }
322
[1395]323 if (strchr(szMsg, ' ') == NULL) {
324 strcat(szMsg, " ");
[1558]325 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]326 }
[327]327
328 sprintf(szMsg + strlen(szMsg),
[613]329 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]330
[1395]331 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
[327]332
[636]333} // Runtime_Error
[327]334
[452]335//=== saymsg: report misc error using passed message ===
[144]336
[551]337APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]338{
[182]339 CHAR szMsg[4096];
[144]340 va_list va;
[137]341
[144]342 va_start(va, pszFmt);
[613]343 szMsg[sizeof(szMsg) - 1] = 0;
[182]344 vsprintf(szMsg, pszFmt, va);
[144]345 va_end(va);
346
[613]347 if (szMsg[sizeof(szMsg) - 1]) {
348 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
349 fflush(stderr);
350 }
[452]351
[613]352 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
353
[636]354} // saymsg
[182]355
[452]356//=== showMsg: display error popup ===
[182]357
[636]358static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
359 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]360{
[613]361 if (wantLog) {
[258]362 fputs(pszMsg, stderr);
363 fputc('\n', stderr);
[614]364 fputc('\n', stderr);
[258]365 fflush(stderr);
366 }
367
[616]368 if (!hwndOwner)
369 hwndOwner = HWND_DESKTOP;
[1395]370 if (!fErrorBeepOff)
371 DosBeep(250, 100);
[144]372
[182]373 return WinMessageBox(HWND_DESKTOP, // Parent
[616]374 hwndOwner,
[551]375 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]376 mb_type | MB_MOVEABLE);
[613]377} // showMsg
[616]378
[636]379//== Win_Error: report Win...() error using passed message string ===
[616]380
[636]381VOID Win_Error(HWND hwndErr, HWND hwndOwner,
382 PCSZ pszSrcFile, UINT uSrcLineNo,
383 PCSZ pszFmt, ...)
[616]384{
[636]385 CHAR szMsg[4096];
[616]386 va_list va;
387
[636]388 // Format callers message
389 va_start(va, pszFmt);
390 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
391 va_end(va);
392
393 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
394 szMsg, TRUE);
395
396} // Win_Error
397
398/**
399 * Output PM error messsage to stderr
400 * This does to same reporting as Win_Error, but bypasses the
401 * message box popup.
402 * Use this version when the popup would hang PM.
403 */
404
405VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
406 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
407{
408 CHAR szMsg[4096];
409 va_list va;
410
411 // Format callers message
412 va_start(va, pszFmt);
413 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
414 va_end(va);
415
416 fputs(szMsg, stderr);
[616]417 fputc('\n', stderr);
[636]418 fputc('\n', stderr);
[616]419 fflush(stderr);
[1395]420 if (!fErrorBeepOff)
421 DosBeep(250, 100);
[616]422
[636]423} // Win_Error_NoMsgBox
[787]424
[1402]425#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.