source: trunk/dll/errutil.c@ 1398

Last change on this file since 1398 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
RevLine 
[121]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
[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
[1398]51#include "init.h" // Data declares
[2]52
[907]53#pragma data_seg(GLOBAL2)
54PSZ DEBUG_STRING;
55
[2]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];
[636]121 ULONG Class; // Error class
122 ULONG action; // Error action
123 ULONG Locus; // Error location
[144]124 ULONG ulMsgLen;
125 CHAR *pszMsgStart;
126 CHAR *psz;
127 va_list va;
[2]128
[144]129 if (!ulRC)
130 return MBID_ENTER; // Should not have been called
[121]131
[144]132 // Format caller's message
133 va_start(va, pszFmt);
[613]134 szMsg[sizeof(szMsg) - 1] = 0;
[182]135 vsprintf(szMsg, pszFmt, va);
[144]136 va_end(va);
[121]137
[613]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
[1395]143 if (strchr(szMsg, ' ') == NULL) {
144 strcat(szMsg, " ");
145 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
146 }
[327]147
[144]148 DosErrClass(ulRC, &Class, &action, &Locus);
149
[182]150 sprintf(szMsg + strlen(szMsg),
[144]151 GetPString(IDS_DOSERR1TEXT),
[636]152 pszSrcFile,
153 uSrcLineNo,
[144]154 ulRC,
155 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
156 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
157 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
[182]158 pszMsgStart = szMsg + strlen(szMsg) + 1;
[144]159 // Get message leaving space for NL separator
[551]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)) {
[144]164 // Got message
165 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
[182]166 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
[144]167 *pszMsgStart = '\"'; // Prefix message text with quote
[182]168
[144]169 psz = pszMsgStart + ulMsgLen; // Point at last char
170 // Chop trailing NL CR TAB
171 while (*psz &&
[551]172 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
[144]173 *psz-- = 0;
174 }
175 strcat(psz, "\""); // Append trailing quote
176
177 // Convert CR and NL combos to single space
178 psz = pszMsgStart;
[551]179 while (*psz) {
180 if (*psz == '\n' || *psz == '\r') {
[144]181 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
182 memmove(psz, psz + 1, strlen(psz));
183 *psz = ' ';
[2]184 }
[144]185 else
186 psz++;
[2]187 }
188 }
[137]189
[613]190 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
191 szMsg, TRUE);
[137]192
[636]193} // Dos_Error
[137]194
[1395]195/*== Dos_Error2: report Dos...() error using passed message id ===
[383]196
[636]197INT Dos_Error2(ULONG mb_type, ULONG ulRC, HWND hwndOwner,
198 PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
[383]199{
[636]200 return Dos_Error(mb_type, ulRC, hwndOwner, pszSrcFile, uSrcLineNo,
[551]201 GetPString(idMsg));
[1395]202} // Dos_Error2 */
[383]203
[636]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
[1395]234 if (strchr(pszBuf, ' ') == NULL) {
235 strcat(pszBuf, " ");
236 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
237 }
[636]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) {
[907]246 ERRORID id = WinGetLastError(hab);
[636]247 psz = pszBuf + strlen(pszBuf);
[904]248 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]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);
[904]261 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]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
[787]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
[452]297//== Runtime_Error: report runtime library error using passed message string ===
[1398]298//If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
[327]299
[551]300VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]301{
302 CHAR szMsg[4096];
303 va_list va;
304
305 // Format caller's message
[1398]306 if (!pszFmt)
307 pszFmt = PCSZ_NODATA;
[327]308 va_start(va, pszFmt);
[613]309 szMsg[sizeof(szMsg) - 1] = 0;
[327]310 vsprintf(szMsg, pszFmt, va);
311 va_end(va);
312
[613]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
[1395]318 if (strchr(szMsg, ' ') == NULL) {
319 strcat(szMsg, " ");
320 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
321 }
[327]322
323 sprintf(szMsg + strlen(szMsg),
[613]324 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]325
[1395]326 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
[327]327
[636]328} // Runtime_Error
[327]329
[452]330//== Runtime_Error2: report runtime library error using passed message id ===
331
[1398]332/*VOID Runtime_Error2(PCSZ pszSrcFile, UINT uSrcLineNo, UINT idMsg)
[383]333{
334 Runtime_Error(pszSrcFile, uSrcLineNo, GetPString(idMsg));
335
[636]336} // Runtime_Error2
[383]337
[1398]338// fixme to be rename to Misc_Error */
[144]339
[452]340//=== saymsg: report misc error using passed message ===
[144]341
[551]342APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]343{
[182]344 CHAR szMsg[4096];
[144]345 va_list va;
[137]346
[144]347 va_start(va, pszFmt);
[613]348 szMsg[sizeof(szMsg) - 1] = 0;
[182]349 vsprintf(szMsg, pszFmt, va);
[144]350 va_end(va);
351
[613]352 if (szMsg[sizeof(szMsg) - 1]) {
353 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
354 fflush(stderr);
355 }
[452]356
[613]357 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
358
[636]359} // saymsg
[182]360
[452]361//=== showMsg: display error popup ===
[182]362
[636]363static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
364 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]365{
[613]366 if (wantLog) {
[258]367 fputs(pszMsg, stderr);
368 fputc('\n', stderr);
[614]369 fputc('\n', stderr);
[258]370 fflush(stderr);
371 }
372
[616]373 if (!hwndOwner)
374 hwndOwner = HWND_DESKTOP;
[1395]375 if (!fErrorBeepOff)
376 DosBeep(250, 100);
[144]377
[182]378 return WinMessageBox(HWND_DESKTOP, // Parent
[616]379 hwndOwner,
[551]380 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]381 mb_type | MB_MOVEABLE);
[613]382} // showMsg
[616]383
[636]384//== Win_Error: report Win...() error using passed message string ===
[616]385
[636]386VOID Win_Error(HWND hwndErr, HWND hwndOwner,
387 PCSZ pszSrcFile, UINT uSrcLineNo,
388 PCSZ pszFmt, ...)
[616]389{
[636]390 CHAR szMsg[4096];
[616]391 va_list va;
392
[636]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
[1395]403/*== Win_Error2: report Win...() error using passed message id ===
[636]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
[1395]410} // Win_Error2 */
[636]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);
[616]431 fputc('\n', stderr);
[636]432 fputc('\n', stderr);
[616]433 fflush(stderr);
[1395]434 if (!fErrorBeepOff)
435 DosBeep(250, 100);
[616]436
[636]437} // Win_Error_NoMsgBox
[787]438
439#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,showMsg,GetHiresTimeer)
Note: See TracBrowser for help on using the repository browser.