source: trunk/dll/errutil.c@ 1401

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

Move embeded strings to PCSZ variables or string table; Eliminate Error2 functions Runtime_Error with NULL format string returns "No data" error. Change declares from PSZ to PCSZ in functions where the variable isn't changed. Added btm as an executable file type in several additional places. Use fProtectOnly to prevent attempt to execute Dos and Win programs on "Protect only" installs in several additional places.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1
2/***********************************************************************
3
4 $Id: errutil.c 1398 2009-02-21 17:43:00Z gyoung $
5
6 Error reporting
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2004, 2008 Steven H. Levine
10
11 12 Aug 04 SHL Comments
12 23 May 05 SHL Move saymsg here
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
16 27 May 05 SHL Rework to use common showMsg
17 14 Aug 05 SHL showMsg: suppress write to stdout if not error message
18 13 Jul 06 SHL Add Runtime_Error
19 22 Jul 06 SHL Optimize calling sequences
20 26 Jul 06 SHL Add ..._Error2
21 16 Aug 06 SHL Tweak message formatting
22 07 Jan 07 GKY Move error strings etc. to string file
23 18 Apr 07 SHL showMsg: correct selective logging checks
24 19 Apr 07 SHL Add DbgMsg
25 20 Apr 07 SHL Correct IDS_GENERR1TEXT formatting
26 23 Apr 07 SHL Add Win_Error_NoMsgBox. Rework others
27 14 Aug 07 SHL Add GetMSecTimer
28 14 Aug 07 SHL Use GetMSecTimer in DbgMsg
29 05 Jan 08 SHL Renamed from error.c to match errutil.h
30 18 Dec 08 SHL Show thread id in DbgMsg
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.
34
35***********************************************************************/
36
37#include <stdio.h>
38#include <string.h>
39#include <stdarg.h>
40
41#define INCL_DOS
42#define INCL_WIN
43#define INCL_DOSERRORS
44#define INCL_DOSPROCESS // PPIB PTIB
45#define INCL_LONGLONG
46
47#include "errutil.h"
48#include "strutil.h" // GetPString
49#include "fm3str.h"
50#include "notebook.h" // fErrorBeepOff
51#include "init.h" // Data declares
52
53#pragma data_seg(GLOBAL2)
54PSZ DEBUG_STRING;
55
56#pragma data_seg(DATA1)
57
58static PSZ pszSrcFile = __FILE__;
59
60static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
61 PCSZ pszSrcFile, UINT uSrcLineNo,
62 PCSZ pszFmt, va_list pva);
63
64static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
65
66//=== DbgMsg: output debug message stderr ===
67
68VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
69{
70 PIB *ppib;
71 TIB *ptib;
72 ULONG ultid;
73 APIRET apiret;
74 va_list va;
75
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
95 apiret = DosGetInfoBlocks(&ptib, &ppib);
96 if (apiret)
97 ultid = 0;
98 else
99 ultid = ptib->tib_ptib2->tib2_ultid;
100
101 // OK for source file name to be null
102 fprintf(stderr, "%s %u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
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);
109 }
110 fputc('\n', stderr);
111 fflush(stderr);
112
113} // DbgMsg
114
115//== Dos_Error: report Dos...() error using passed message string ===
116
117INT Dos_Error(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
118 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
119{
120 CHAR szMsg[4096];
121 ULONG Class; // Error class
122 ULONG action; // Error action
123 ULONG Locus; // Error location
124 ULONG ulMsgLen;
125 CHAR *pszMsgStart;
126 CHAR *psz;
127 va_list va;
128
129 if (!ulRC)
130 return MBID_ENTER; // Should not have been called
131
132 // Format caller's message
133 va_start(va, pszFmt);
134 szMsg[sizeof(szMsg) - 1] = 0;
135 vsprintf(szMsg, pszFmt, va);
136 va_end(va);
137
138 if (szMsg[sizeof(szMsg) - 1]) {
139 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
140 fflush(stderr);
141 }
142
143 if (strchr(szMsg, ' ') == NULL) {
144 strcat(szMsg, " ");
145 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
146 }
147
148 DosErrClass(ulRC, &Class, &action, &Locus);
149
150 sprintf(szMsg + strlen(szMsg),
151 GetPString(IDS_DOSERR1TEXT),
152 pszSrcFile,
153 uSrcLineNo,
154 ulRC,
155 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
156 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
157 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
158 pszMsgStart = szMsg + strlen(szMsg) + 1;
159 // Get message leaving space for NL separator
160 if (!DosGetMessage
161 (NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC, "OSO001.MSG", &ulMsgLen)
162 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, ulRC,
163 "OSO001H.MSG", &ulMsgLen)) {
164 // Got message
165 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
166 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
167 *pszMsgStart = '\"'; // Prefix message text with quote
168
169 psz = pszMsgStart + ulMsgLen; // Point at last char
170 // Chop trailing NL CR TAB
171 while (*psz &&
172 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
173 *psz-- = 0;
174 }
175 strcat(psz, "\""); // Append trailing quote
176
177 // Convert CR and NL combos to single space
178 psz = pszMsgStart;
179 while (*psz) {
180 if (*psz == '\n' || *psz == '\r') {
181 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
182 memmove(psz, psz + 1, strlen(psz));
183 *psz = ' ';
184 }
185 else
186 psz++;
187 }
188 }
189
190 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
191 szMsg, TRUE);
192
193} // Dos_Error
194
195/*== Dos_Error2: report Dos...() error using passed message id ===
196
197INT Dos_Error2(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
198 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
199{
200 return Dos_Error(mb_type, ulRC, hwndOwner, pszSrcFile, uSrcLineNo,
201 GetPString(idMsg));
202} // Dos_Error2 */
203
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
234 if (strchr(pszBuf, ' ') == NULL) {
235 strcat(pszBuf, " ");
236 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
237 }
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) {
246 ERRORID id = WinGetLastError(hab);
247 psz = pszBuf + strlen(pszBuf);
248 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
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);
261 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
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
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
297//== Runtime_Error: report runtime library error using passed message string ===
298//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
299
300VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
301{
302 CHAR szMsg[4096];
303 va_list va;
304
305 // Format caller's message
306 if (!pszFmt)
307 pszFmt = PCSZ_NODATA;
308 va_start(va, pszFmt);
309 szMsg[sizeof(szMsg) - 1] = 0;
310 vsprintf(szMsg, pszFmt, va);
311 va_end(va);
312
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
318 if (strchr(szMsg, ' ') == NULL) {
319 strcat(szMsg, " ");
320 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
321 }
322
323 sprintf(szMsg + strlen(szMsg),
324 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
325
326 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
327
328} // Runtime_Error
329
330//== Runtime_Error2: report runtime library error using passed message id ===
331
332/*VOID Runtime_Error2(PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
333{
334 Runtime_Error(pszSrcFile, uSrcLineNo, GetPString(idMsg));
335
336} // Runtime_Error2
337
338// fixme to be rename to Misc_Error */
339
340//=== saymsg: report misc error using passed message ===
341
342APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
343{
344 CHAR szMsg[4096];
345 va_list va;
346
347 va_start(va, pszFmt);
348 szMsg[sizeof(szMsg) - 1] = 0;
349 vsprintf(szMsg, pszFmt, va);
350 va_end(va);
351
352 if (szMsg[sizeof(szMsg) - 1]) {
353 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
354 fflush(stderr);
355 }
356
357 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
358
359} // saymsg
360
361//=== showMsg: display error popup ===
362
363static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
364 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
365{
366 if (wantLog) {
367 fputs(pszMsg, stderr);
368 fputc('\n', stderr);
369 fputc('\n', stderr);
370 fflush(stderr);
371 }
372
373 if (!hwndOwner)
374 hwndOwner = HWND_DESKTOP;
375 if (!fErrorBeepOff)
376 DosBeep(250, 100);
377
378 return WinMessageBox(HWND_DESKTOP, // Parent
379 hwndOwner,
380 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
381 mb_type | MB_MOVEABLE);
382} // showMsg
383
384//== Win_Error: report Win...() error using passed message string ===
385
386VOID Win_Error(HWND hwndErr, HWND hwndOwner,
387 PCSZ pszSrcFile, UINT uSrcLineNo,
388 PCSZ pszFmt, ...)
389{
390 CHAR szMsg[4096];
391 va_list va;
392
393 // Format callers message
394 va_start(va, pszFmt);
395 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
396 va_end(va);
397
398 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
399 szMsg, TRUE);
400
401} // Win_Error
402
403/*== Win_Error2: report Win...() error using passed message id ===
404
405VOID Win_Error2(HWND hwndErr, HWND hwndOwner,
406 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
407{
408 Win_Error(hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, GetPString(idMsg));
409
410} // Win_Error2 */
411
412/**
413 * Output PM error messsage to stderr
414 * This does to same reporting as Win_Error, but bypasses the
415 * message box popup.
416 * Use this version when the popup would hang PM.
417 */
418
419VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
420 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
421{
422 CHAR szMsg[4096];
423 va_list va;
424
425 // Format callers message
426 va_start(va, pszFmt);
427 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo, pszFmt, va);
428 va_end(va);
429
430 fputs(szMsg, stderr);
431 fputc('\n', stderr);
432 fputc('\n', stderr);
433 fflush(stderr);
434 if (!fErrorBeepOff)
435 DosBeep(250, 100);
436
437} // Win_Error_NoMsgBox
438
439#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,GetHiresTimeer)
Note: See TracBrowser for help on using the repository browser.