source: trunk/dll/errutil.c@ 1880

Last change on this file since 1880 was 1880, checked in by Gregg Young, 10 years ago

Remove dead code and comments from remaining c files. #if 0 and #if NEVER were not addressed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
RevLine 
[121]1
2/***********************************************************************
3
4 $Id: errutil.c 1880 2015-10-12 18:26:16Z gyoung $
5
6 Error reporting
7
8 Copyright (c) 1993-98 M. Kimes
[1840]9 Copyright (c) 2004, 2015 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
[1686]38 10 Mar 13 GKY Improvrd readonly check on delete to allow cancel and don't ask again options
[1698]39 Added saymsg2 for this purpose
40 07 Nov 13 SHL Update comments
[1718]41 15 Feb 14 GKY Improvements to saymsg2 some code cleanup
[1722]42 16 Feb 14 GKY Rework readonly check on delete code so it actually works in a logical way
43 and so it works with move to trashcan inabled.
[1840]44 09 Nov 13 SHL Use GetTidForThread in DbgMsg and tweak for for editors that understand file:line
[121]45
46***********************************************************************/
47
[907]48#include <stdio.h>
49#include <string.h>
50#include <stdarg.h>
[1686]51#include <stdlib.h>
[907]52
[2]53#define INCL_DOS
[1373]54#define INCL_WIN
[2]55#define INCL_DOSERRORS
[1373]56#define INCL_DOSPROCESS // PPIB PTIB
[1395]57#define INCL_LONGLONG
[2]58
[907]59#include "errutil.h"
60#include "strutil.h" // GetPString
[2]61#include "fm3str.h"
[1558]62#include "notebook.h" // fErrorBeepOff
63#include "init.h" // Data declares
[1840]64#include "misc.h" // GetTidForThread
[1698]65#include "wrappers.h" // xmallocz
[1722]66#include "fm3dll2.h"
[2]67
68#pragma data_seg(DATA1)
69
[787]70static PSZ pszSrcFile = __FILE__;
71
[636]72static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
73 PCSZ pszSrcFile, UINT uSrcLineNo,
74 PCSZ pszFmt, va_list pva);
75
[613]76static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
[2]77
[1698]78/**
79 * Format debug message and output to stderr
80 * @note: Local errors also written to stderr
81 */
[144]82
[636]83VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]84{
[1373]85 ULONG ultid;
[144]86 va_list va;
[2]87
[787]88#if 1 // fixme to be selectable
89
90 static ULONG ul1stMSec;
91
92 ULONG msec = GetMSecTimer();
93 ULONG delta;
94
95 if (!ul1stMSec) {
[1880]96 ul1stMSec = msec; // Avoid big delta 1st time
[787]97 }
98
99 delta = msec - ul1stMSec;
100 fprintf(stderr, "%03lu.%03lu ", delta / 1000, delta % 1000);
101
102#endif
103
[1840]104 ultid = GetTidForThread();
[1373]105
[636]106 // OK for source file name to be null
[1840]107 // 2015-08-08 SHL Use file:line for editors that support it
108 fprintf(stderr, "%s:%u (%lu)", pszSrcFile ? pszSrcFile : "n/a", uSrcLineNo, ultid);
[636]109 // If format null want just file and line
110 if (pszFmt) {
111 fputc(' ', stderr);
112 va_start(va, pszFmt);
113 vfprintf(stderr, pszFmt, va);
114 va_end(va);
[613]115 }
[636]116 fputc('\n', stderr);
117 fflush(stderr);
[613]118
[636]119} // DbgMsg
[327]120
[1698]121/**
122 * Format Dos...() error and output using showMsg
123 * @note: Local errors written directly to stderr
124 */
[144]125
[1558]126// 2010-12-01 SHL fixme for ULONG to be APIRET
127
128INT Dos_Error(ULONG mb_type, ULONG apiret, HWND hwndOwner,
[636]129 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[121]130{
[182]131 CHAR szMsg[4096];
[1450]132 CHAR szMsgFile[20], szMsgFileH[20];
[636]133 ULONG Class; // Error class
134 ULONG action; // Error action
[1558]135 ULONG Locus; // Error location
[144]136 ULONG ulMsgLen;
[1558]137 APIRET mapped_apiret;
[144]138 CHAR *pszMsgStart;
139 CHAR *psz;
140 va_list va;
[2]141
[1558]142 if (!apiret)
[144]143 return MBID_ENTER; // Should not have been called
[121]144
[144]145 // Format caller's message
146 va_start(va, pszFmt);
[613]147 szMsg[sizeof(szMsg) - 1] = 0;
[182]148 vsprintf(szMsg, pszFmt, va);
[144]149 va_end(va);
[121]150
[613]151 if (szMsg[sizeof(szMsg) - 1]) {
152 fprintf(stderr, "Buffer overflow in Dos_Error - need %u bytes\n", strlen(szMsg) + 1);
153 fflush(stderr);
154 }
155
[1395]156 if (strchr(szMsg, ' ') == NULL) {
157 strcat(szMsg, " ");
[1558]158 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]159 }
[327]160
[1558]161 DosErrClass(apiret, &Class, &action, &Locus);
[144]162
[182]163 sprintf(szMsg + strlen(szMsg),
[144]164 GetPString(IDS_DOSERR1TEXT),
[636]165 pszSrcFile,
166 uSrcLineNo,
[1558]167 apiret,
[144]168 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
169 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
[1558]170 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
[182]171 pszMsgStart = szMsg + strlen(szMsg) + 1;
[1449]172 strcpy(szMsgFile, "OSO001.MSG");
173 strcpy(szMsgFileH, "OSO001H.MSG");
[144]174 // Get message leaving space for NL separator
[1558]175 // 2010-12-01 SHL Handle cases where message file message does not make sense relative to API error
176 switch (apiret) {
177 case ERROR_TIMEOUT:
178 mapped_apiret = ERROR_SEM_TIMEOUT; // Assume semaphore timeout
179 break;
180 default:
181 mapped_apiret = apiret;
182 }
183 if (!DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, mapped_apiret, szMsgFile, &ulMsgLen)
184 || !DosGetMessage(NULL, 0L, (PCHAR) pszMsgStart + 1, 1024, mapped_apiret,
185 szMsgFileH, &ulMsgLen)) {
[144]186 // Got message
187 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
[182]188 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
[144]189 *pszMsgStart = '\"'; // Prefix message text with quote
[182]190
[144]191 psz = pszMsgStart + ulMsgLen; // Point at last char
192 // Chop trailing NL CR TAB
193 while (*psz &&
[551]194 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
[144]195 *psz-- = 0;
196 }
197 strcat(psz, "\""); // Append trailing quote
198
199 // Convert CR and NL combos to single space
200 psz = pszMsgStart;
[551]201 while (*psz) {
202 if (*psz == '\n' || *psz == '\r') {
[144]203 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
204 memmove(psz, psz + 1, strlen(psz));
205 *psz = ' ';
[2]206 }
[144]207 else
208 psz++;
[2]209 }
210 }
[137]211
[613]212 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
213 szMsg, TRUE);
[137]214
[636]215} // Dos_Error
[137]216
[636]217/**
218 * Format last PM error into passed buffer
219 */
220
221static VOID formatWinError(PSZ pszBuf, UINT cBufBytes,
222 HWND hwndErr, HWND hwndOwner,
223 PCSZ pszSrcFile, UINT uSrcLineNo,
224 PCSZ pszFmt, va_list pva)
225{
[1673]226 PERRINFO pErrInfoBlk; // Pointer to ERRINFO structure filled by WinGetErrorInfo
227 PSZ pszOffset; // Pointer to current error message returned by WinGetErrorInfo
[636]228 PSZ psz;
229 HAB hab;
230
231 if (hwndErr == NULLHANDLE)
232 hab = (HAB)0;
233 else
234 hab = WinQueryAnchorBlock(hwndErr);
235
236 // Format callers message
237 pszBuf[cBufBytes - 1] = 0;
238 vsprintf(pszBuf, pszFmt, pva);
239
240 if (pszBuf[cBufBytes - 1]) {
[1718]241 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n",
242 strlen(pszBuf) + 1);
[636]243 fflush(stderr);
244 }
245
[1395]246 if (strchr(pszBuf, ' ') == NULL) {
247 strcat(pszBuf, " ");
[1558]248 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]249 }
[636]250
251 // Append file name and line number and trailing space
252 sprintf(pszBuf + strlen(pszBuf),
253 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
254
255 // Get last PM error for the current thread
256 pErrInfoBlk = WinGetErrorInfo(hab);
257 if (!pErrInfoBlk) {
[907]258 ERRORID id = WinGetLastError(hab);
[636]259 psz = pszBuf + strlen(pszBuf);
[904]260 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
[636]261 }
262 else {
263 if (!hwndOwner)
264 hwndOwner = HWND_DESKTOP;
[1673]265 // Find message offset in array of message offsets Assume 1 message - fixme?
[636]266 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
[1673]267 // Address error message in array of messages and append error message to source code linenumber
[636]268 psz = pszBuf + strlen(pszBuf);
[904]269 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
[636]270 psz += strlen(psz);
271 strcpy(psz, ((PSZ) pErrInfoBlk) + *(PSHORT) pszOffset);
272 psz += strlen(psz);
273 // Chop trailing mush
274 psz--;
275 while (*psz == '\r' || *psz == '\n' || *psz == ' ')
276 *psz-- = 0;
277 if (*psz)
278 psz++;
279 strcpy(psz, "\"");
280 WinFreeErrorInfo(pErrInfoBlk); // Free resource segment
281 }
282
283} // formatWinError
284
[787]285/**
286 * Return millisecond timer value
287 * Resolution is milliseconds, but accuracy will be less
288 * depending on systems settings
289 */
290
291ULONG GetMSecTimer(void)
292{
293 ULONG msec;
294
295 APIRET rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
296 &msec, sizeof(msec));
297 if (rc) {
298 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
299 "DosQuerySysInfo");
300 msec = 0;
301 }
302 return msec;
303}
304
[1698]305/**
306 * Format runtime error message and output using showMsg
307 * @note: Local errors written directly to stderr
308 * @note: If pszFmt is NULL a No Data error message is returned GKY 20 Feb 09 (Replaces Runtime_Error2)
309 */
[327]310
[551]311VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
[327]312{
313 CHAR szMsg[4096];
314 va_list va;
315
316 // Format caller's message
[1398]317 if (!pszFmt)
318 pszFmt = PCSZ_NODATA;
[327]319 va_start(va, pszFmt);
[613]320 szMsg[sizeof(szMsg) - 1] = 0;
[327]321 vsprintf(szMsg, pszFmt, va);
322 va_end(va);
323
[613]324 if (szMsg[sizeof(szMsg) - 1]) {
325 fprintf(stderr, "Buffer overflow in Runtime_Error - need %u bytes\n", strlen(szMsg) + 1);
326 fflush(stderr);
327 }
328
[1395]329 if (strchr(szMsg, ' ') == NULL) {
330 strcat(szMsg, " ");
[1558]331 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
[1395]332 }
[327]333
334 sprintf(szMsg + strlen(szMsg),
[613]335 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
[327]336
[1395]337 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
[327]338
[636]339} // Runtime_Error
[327]340
[1698]341/**
342 * Format message and output using showMsg
343 * @note: Local errors written directly to stderr
344 */
[144]345
[551]346APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
[137]347{
[182]348 CHAR szMsg[4096];
[144]349 va_list va;
[137]350
[144]351 va_start(va, pszFmt);
[613]352 szMsg[sizeof(szMsg) - 1] = 0;
[182]353 vsprintf(szMsg, pszFmt, va);
[144]354 va_end(va);
355
[613]356 if (szMsg[sizeof(szMsg) - 1]) {
357 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
358 fflush(stderr);
359 }
[452]360
[613]361 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
362
[636]363} // saymsg
[182]364
[1698]365/**
366 * Format message with custom buttons and output using showMsg
367 * Local errors written to stderr
368 */
369
[1718]370APIRET saymsg2(PCSZ pszButtonNames, int DefaultButton, HWND hwnd,
371 PCSZ pszTitle, PCSZ pszFmt, ...)
[1686]372{
[1698]373 ULONG i;
374 APIRET rc;
[1686]375 CHAR szMsg[4096];
376 va_list va;
[1698]377 MB2INFO *pmbInfo;
378 MB2D mb2dBut[4];
379 ULONG ulInfoSize = (sizeof(MB2INFO) + (sizeof(MB2D) * 3));
[1686]380
381 va_start(va, pszFmt);
382 szMsg[sizeof(szMsg) - 1] = 0;
383 vsprintf(szMsg, pszFmt, va);
384 va_end(va);
385
386 if (szMsg[sizeof(szMsg) - 1]) {
387 fprintf(stderr, "Buffer overflow in saymsg2 - need %u bytes\n", strlen(szMsg) + 1);
388 fflush(stderr);
389 }
390
391 memset(mb2dBut, 0, sizeof(MB2D) * 4);
[1718]392 strcpy(mb2dBut[0].achText,GetPString(IDS_MB2DYES));
393 strcpy(mb2dBut[1].achText,GetPString(IDS_MB2DYESDONTASK));
394 strcpy(mb2dBut[2].achText,GetPString(IDS_MB2DNO));
395 strcpy(mb2dBut[3].achText,GetPString(IDS_MB2DCANCELOP));
[1722]396 mb2dBut[0].idButton = SM2_YES;
397 mb2dBut[1].idButton = SM2_DONTASK;
398 mb2dBut[2].idButton = SM2_NO;
399 mb2dBut[3].idButton = SM2_CANCEL;
[1686]400 if (DefaultButton)
401 mb2dBut[DefaultButton - 1].flStyle = BS_DEFAULT;
402 pmbInfo = xmallocz(ulInfoSize, pszSrcFile, __LINE__);
403 if (pmbInfo) {
[1698]404 pmbInfo->cb = ulInfoSize;
[1686]405 pmbInfo->hIcon = 0;
406 pmbInfo->cButtons = 4;
[1722]407 pmbInfo->flStyle = MB_MOVEABLE | MB_ICONQUESTION ;
[1686]408 pmbInfo->hwndNotify = NULLHANDLE;
409 for (i = 0; i < 4; i++) {
410 memcpy( pmbInfo->mb2d+i , mb2dBut+i , sizeof(MB2D));
[1698]411 }
[1686]412 rc = WinMessageBox2(HWND_DESKTOP, hwnd,
[1722]413 szMsg, pszTitle, SM2_DIALOG,
[1718]414 pmbInfo);
[1722]415 WinSetFocus(HWND_DESKTOP, SM2_DIALOG);
[1686]416 free(pmbInfo);
417 return rc;
418 }
419 return MBID_ERROR;
420}
421
[1698]422/**
423 * Display message in popup message box
424 * Optionally writes formatted message to stderr
425 */
[182]426
[636]427static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
428 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
[182]429{
[613]430 if (wantLog) {
[258]431 fputs(pszMsg, stderr);
432 fputc('\n', stderr);
[614]433 fputc('\n', stderr);
[258]434 fflush(stderr);
435 }
436
[616]437 if (!hwndOwner)
438 hwndOwner = HWND_DESKTOP;
[1395]439 if (!fErrorBeepOff)
440 DosBeep(250, 100);
[144]441
[182]442 return WinMessageBox(HWND_DESKTOP, // Parent
[616]443 hwndOwner,
[551]444 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
[182]445 mb_type | MB_MOVEABLE);
[613]446} // showMsg
[616]447
[1698]448/**
449 * Format Win...() error and output using showMsg
450 */
[616]451
[636]452VOID Win_Error(HWND hwndErr, HWND hwndOwner,
453 PCSZ pszSrcFile, UINT uSrcLineNo,
454 PCSZ pszFmt, ...)
[616]455{
[636]456 CHAR szMsg[4096];
[616]457 va_list va;
458
[636]459 // Format callers message
460 va_start(va, pszFmt);
[1718]461 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile,
462 uSrcLineNo, pszFmt, va);
[636]463 va_end(va);
464
465 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
466 szMsg, TRUE);
467
468} // Win_Error
469
470/**
[1698]471 * Format PM error messsage and output to stderr
472 * This does the same reporting as Win_Error, but bypasses the
[636]473 * message box popup.
474 * Use this version when the popup would hang PM.
475 */
476
477VOID Win_Error_NoMsgBox(HWND hwndErr, HWND hwndOwner,
478 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
479{
480 CHAR szMsg[4096];
481 va_list va;
482
483 // Format callers message
484 va_start(va, pszFmt);
[1718]485 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo,
486 pszFmt, va);
[636]487 va_end(va);
488
489 fputs(szMsg, stderr);
[616]490 fputc('\n', stderr);
[636]491 fputc('\n', stderr);
[616]492 fflush(stderr);
[1395]493 if (!fErrorBeepOff)
494 DosBeep(250, 100);
[616]495
[636]496} // Win_Error_NoMsgBox
[787]497
[1718]498#pragma alloc_text(ERROR,Win_Error,Dos_Error,saymsg,saymsg2,showMsg,Runtime_Error,GetMSecTimer)
Note: See TracBrowser for help on using the repository browser.