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
Line 
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
9 Copyright (c) 2004, 2015 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 08 Mar 09 GKY Remove Dos_Error2 (unused) and Runtime_Error2 (no advantage over using Runtime_Error)
35 23 Jul 09 GKY Add low mem buffers for the msg file name so DosGetMessage
36 works in HIMEM builds
37 01 Dec 10 SHL Dos_Error - remap API errors code that with odd oso001*.msg messages
38 10 Mar 13 GKY Improvrd readonly check on delete to allow cancel and don't ask again options
39 Added saymsg2 for this purpose
40 07 Nov 13 SHL Update comments
41 15 Feb 14 GKY Improvements to saymsg2 some code cleanup
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.
44 09 Nov 13 SHL Use GetTidForThread in DbgMsg and tweak for for editors that understand file:line
45
46***********************************************************************/
47
48#include <stdio.h>
49#include <string.h>
50#include <stdarg.h>
51#include <stdlib.h>
52
53#define INCL_DOS
54#define INCL_WIN
55#define INCL_DOSERRORS
56#define INCL_DOSPROCESS // PPIB PTIB
57#define INCL_LONGLONG
58
59#include "errutil.h"
60#include "strutil.h" // GetPString
61#include "fm3str.h"
62#include "notebook.h" // fErrorBeepOff
63#include "init.h" // Data declares
64#include "misc.h" // GetTidForThread
65#include "wrappers.h" // xmallocz
66#include "fm3dll2.h"
67
68#pragma data_seg(DATA1)
69
70static PSZ pszSrcFile = __FILE__;
71
72static VOID formatWinError(PSZ pszBuf, UINT cBufBytes, HWND hwndErr, HWND hwndOwner,
73 PCSZ pszSrcFile, UINT uSrcLineNo,
74 PCSZ pszFmt, va_list pva);
75
76static APIRET showMsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog);
77
78/**
79 * Format debug message and output to stderr
80 * @note: Local errors also written to stderr
81 */
82
83VOID DbgMsg(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
84{
85 ULONG ultid;
86 va_list va;
87
88#if 1 // fixme to be selectable
89
90 static ULONG ul1stMSec;
91
92 ULONG msec = GetMSecTimer();
93 ULONG delta;
94
95 if (!ul1stMSec) {
96 ul1stMSec = msec; // Avoid big delta 1st time
97 }
98
99 delta = msec - ul1stMSec;
100 fprintf(stderr, "%03lu.%03lu ", delta / 1000, delta % 1000);
101
102#endif
103
104 ultid = GetTidForThread();
105
106 // OK for source file name to be null
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);
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);
115 }
116 fputc('\n', stderr);
117 fflush(stderr);
118
119} // DbgMsg
120
121/**
122 * Format Dos...() error and output using showMsg
123 * @note: Local errors written directly to stderr
124 */
125
126// 2010-12-01 SHL fixme for ULONG to be APIRET
127
128INT Dos_Error(ULONG mb_type, ULONG apiret, HWND hwndOwner,
129 PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
130{
131 CHAR szMsg[4096];
132 CHAR szMsgFile[20], szMsgFileH[20];
133 ULONG Class; // Error class
134 ULONG action; // Error action
135 ULONG Locus; // Error location
136 ULONG ulMsgLen;
137 APIRET mapped_apiret;
138 CHAR *pszMsgStart;
139 CHAR *psz;
140 va_list va;
141
142 if (!apiret)
143 return MBID_ENTER; // Should not have been called
144
145 // Format caller's message
146 va_start(va, pszFmt);
147 szMsg[sizeof(szMsg) - 1] = 0;
148 vsprintf(szMsg, pszFmt, va);
149 va_end(va);
150
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
156 if (strchr(szMsg, ' ') == NULL) {
157 strcat(szMsg, " ");
158 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
159 }
160
161 DosErrClass(apiret, &Class, &action, &Locus);
162
163 sprintf(szMsg + strlen(szMsg),
164 GetPString(IDS_DOSERR1TEXT),
165 pszSrcFile,
166 uSrcLineNo,
167 apiret,
168 GetPString(IDS_ERRCLASS1TEXT + (Class - 1)),
169 GetPString(IDS_ERRACTION1TEXT + (action - 1)),
170 GetPString(IDS_ERRLOCUS1TEXT + (Locus - 1)));
171 pszMsgStart = szMsg + strlen(szMsg) + 1;
172 strcpy(szMsgFile, "OSO001.MSG");
173 strcpy(szMsgFileH, "OSO001H.MSG");
174 // Get message leaving space for NL separator
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)) {
186 // Got message
187 pszMsgStart[ulMsgLen + 1] = 0; // Terminate
188 *(pszMsgStart - 1) = '\n'; // Stuff NL before message text
189 *pszMsgStart = '\"'; // Prefix message text with quote
190
191 psz = pszMsgStart + ulMsgLen; // Point at last char
192 // Chop trailing NL CR TAB
193 while (*psz &&
194 (*psz == '\r' || *psz == '\n' || *psz == ' ' || *psz == '\t')) {
195 *psz-- = 0;
196 }
197 strcat(psz, "\""); // Append trailing quote
198
199 // Convert CR and NL combos to single space
200 psz = pszMsgStart;
201 while (*psz) {
202 if (*psz == '\n' || *psz == '\r') {
203 while (*(psz + 1) == '\n' || *(psz + 1) == '\r')
204 memmove(psz, psz + 1, strlen(psz));
205 *psz = ' ';
206 }
207 else
208 psz++;
209 }
210 }
211
212 return showMsg(mb_type | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_DOSERR2TEXT),
213 szMsg, TRUE);
214
215} // Dos_Error
216
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{
226 PERRINFO pErrInfoBlk; // Pointer to ERRINFO structure filled by WinGetErrorInfo
227 PSZ pszOffset; // Pointer to current error message returned by WinGetErrorInfo
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]) {
241 fprintf(stderr, "Buffer overflow in formatWinError - need %u bytes\n",
242 strlen(pszBuf) + 1);
243 fflush(stderr);
244 }
245
246 if (strchr(pszBuf, ' ') == NULL) {
247 strcat(pszBuf, " ");
248 strcat(pszBuf, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
249 }
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) {
258 ERRORID id = WinGetLastError(hab);
259 psz = pszBuf + strlen(pszBuf);
260 sprintf(psz, " WinGetErrorInfo failed (%u)", id);
261 }
262 else {
263 if (!hwndOwner)
264 hwndOwner = HWND_DESKTOP;
265 // Find message offset in array of message offsets Assume 1 message - fixme?
266 pszOffset = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
267 // Address error message in array of messages and append error message to source code linenumber
268 psz = pszBuf + strlen(pszBuf);
269 sprintf(psz, " #0x%04x \"", ERRORIDERROR(pErrInfoBlk->idError));
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
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
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 */
310
311VOID Runtime_Error(PCSZ pszSrcFile, UINT uSrcLineNo, PCSZ pszFmt, ...)
312{
313 CHAR szMsg[4096];
314 va_list va;
315
316 // Format caller's message
317 if (!pszFmt)
318 pszFmt = PCSZ_NODATA;
319 va_start(va, pszFmt);
320 szMsg[sizeof(szMsg) - 1] = 0;
321 vsprintf(szMsg, pszFmt, va);
322 va_end(va);
323
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
329 if (strchr(szMsg, ' ') == NULL) {
330 strcat(szMsg, " ");
331 strcat(szMsg, GetPString(IDS_FAILEDTEXT)); // Assume simple function name
332 }
333
334 sprintf(szMsg + strlen(szMsg),
335 GetPString(IDS_GENERR1TEXT), pszSrcFile, uSrcLineNo);
336
337 showMsg(MB_ICONEXCLAMATION, HWND_DESKTOP, GetPString(IDS_DEBUG_STRING), szMsg, TRUE);
338
339} // Runtime_Error
340
341/**
342 * Format message and output using showMsg
343 * @note: Local errors written directly to stderr
344 */
345
346APIRET saymsg(ULONG mb_type, HWND hwnd, PCSZ pszTitle, PCSZ pszFmt, ...)
347{
348 CHAR szMsg[4096];
349 va_list va;
350
351 va_start(va, pszFmt);
352 szMsg[sizeof(szMsg) - 1] = 0;
353 vsprintf(szMsg, pszFmt, va);
354 va_end(va);
355
356 if (szMsg[sizeof(szMsg) - 1]) {
357 fprintf(stderr, "Buffer overflow in saymsg - need %u bytes\n", strlen(szMsg) + 1);
358 fflush(stderr);
359 }
360
361 return showMsg(mb_type, hwnd, pszTitle, szMsg, FALSE);
362
363} // saymsg
364
365/**
366 * Format message with custom buttons and output using showMsg
367 * Local errors written to stderr
368 */
369
370APIRET saymsg2(PCSZ pszButtonNames, int DefaultButton, HWND hwnd,
371 PCSZ pszTitle, PCSZ pszFmt, ...)
372{
373 ULONG i;
374 APIRET rc;
375 CHAR szMsg[4096];
376 va_list va;
377 MB2INFO *pmbInfo;
378 MB2D mb2dBut[4];
379 ULONG ulInfoSize = (sizeof(MB2INFO) + (sizeof(MB2D) * 3));
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);
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));
396 mb2dBut[0].idButton = SM2_YES;
397 mb2dBut[1].idButton = SM2_DONTASK;
398 mb2dBut[2].idButton = SM2_NO;
399 mb2dBut[3].idButton = SM2_CANCEL;
400 if (DefaultButton)
401 mb2dBut[DefaultButton - 1].flStyle = BS_DEFAULT;
402 pmbInfo = xmallocz(ulInfoSize, pszSrcFile, __LINE__);
403 if (pmbInfo) {
404 pmbInfo->cb = ulInfoSize;
405 pmbInfo->hIcon = 0;
406 pmbInfo->cButtons = 4;
407 pmbInfo->flStyle = MB_MOVEABLE | MB_ICONQUESTION ;
408 pmbInfo->hwndNotify = NULLHANDLE;
409 for (i = 0; i < 4; i++) {
410 memcpy( pmbInfo->mb2d+i , mb2dBut+i , sizeof(MB2D));
411 }
412 rc = WinMessageBox2(HWND_DESKTOP, hwnd,
413 szMsg, pszTitle, SM2_DIALOG,
414 pmbInfo);
415 WinSetFocus(HWND_DESKTOP, SM2_DIALOG);
416 free(pmbInfo);
417 return rc;
418 }
419 return MBID_ERROR;
420}
421
422/**
423 * Display message in popup message box
424 * Optionally writes formatted message to stderr
425 */
426
427static APIRET showMsg(ULONG mb_type, HWND hwndOwner,
428 PCSZ pszTitle, PCSZ pszMsg, BOOL wantLog)
429{
430 if (wantLog) {
431 fputs(pszMsg, stderr);
432 fputc('\n', stderr);
433 fputc('\n', stderr);
434 fflush(stderr);
435 }
436
437 if (!hwndOwner)
438 hwndOwner = HWND_DESKTOP;
439 if (!fErrorBeepOff)
440 DosBeep(250, 100);
441
442 return WinMessageBox(HWND_DESKTOP, // Parent
443 hwndOwner,
444 (PSZ) pszMsg, (PSZ) pszTitle, 0, // help id
445 mb_type | MB_MOVEABLE);
446} // showMsg
447
448/**
449 * Format Win...() error and output using showMsg
450 */
451
452VOID Win_Error(HWND hwndErr, HWND hwndOwner,
453 PCSZ pszSrcFile, UINT uSrcLineNo,
454 PCSZ pszFmt, ...)
455{
456 CHAR szMsg[4096];
457 va_list va;
458
459 // Format callers message
460 va_start(va, pszFmt);
461 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile,
462 uSrcLineNo, pszFmt, va);
463 va_end(va);
464
465 showMsg(MB_ENTER | MB_ICONEXCLAMATION, hwndOwner, GetPString(IDS_GENERR2TEXT),
466 szMsg, TRUE);
467
468} // Win_Error
469
470/**
471 * Format PM error messsage and output to stderr
472 * This does the same reporting as Win_Error, but bypasses the
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);
485 formatWinError(szMsg, sizeof(szMsg), hwndErr, hwndOwner, pszSrcFile, uSrcLineNo,
486 pszFmt, va);
487 va_end(va);
488
489 fputs(szMsg, stderr);
490 fputc('\n', stderr);
491 fputc('\n', stderr);
492 fflush(stderr);
493 if (!fErrorBeepOff)
494 DosBeep(250, 100);
495
496} // Win_Error_NoMsgBox
497
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.