Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

740 lines
17 KiB

  1. /*** error.c - error handling functions
  2. *
  3. * Copyright <C> 1989, Microsoft Corporation
  4. *
  5. * Purpose:
  6. * This module contains all error message functions and variuos
  7. * functions that check if errror condition has occured.
  8. *
  9. * This Module contains Proprietary Information of Microsoft
  10. * Corporation and should be treated as Confidential.
  11. *
  12. * Revision History:
  13. *
  14. * [WJK] 28-Jun-1990 Created
  15. *
  16. *************************************************************************/
  17. #include <minlit.h> /* Types, constants */
  18. #include <bndtrn.h> /* More types and constants */
  19. #include <bndrel.h> /* Types and constants */
  20. #include <lnkio.h> /* Linker I/O definitions */
  21. #include <lnkmsg.h> /* Error messages */
  22. #include <nmsg.h> /* Near message strings */
  23. #include <extern.h> /* External declarations */
  24. #include <string.h>
  25. #if (defined(WIN_NT) OR defined(DOSX32)) AND (NOT defined( _WIN32 ))
  26. #define i386
  27. #endif
  28. #include <stdarg.h>
  29. #if EXE386
  30. #include <exe386.h>
  31. #endif
  32. #if WIN_3
  33. #include <windows.h>
  34. #endif
  35. #if NEWIO
  36. #include <errno.h> /* System error codes */
  37. #endif
  38. #define DEBUG_WIN FALSE
  39. #if DEBUG_WIN
  40. char szDebugBuffer[80];
  41. #define DEBUGW(parm1,parm2)\
  42. {\
  43. wsprintf(szDebugBuffer,parm1,(char far*)parm2);\
  44. OutputDebugString(szDebugBuffer);\
  45. }
  46. #else
  47. #define DEBUGW(parm1,parm2)
  48. #endif
  49. #if OSEGEXE AND NOT QCLINK
  50. extern int yylineno; /* Current line in definitions file */
  51. #else
  52. #define yylineno -1
  53. #endif
  54. #if AUTOVM
  55. extern BYTE FAR * NEAR FetchSym1(RBTYPE rb, WORD Dirty);
  56. #define FETCHSYM FetchSym1
  57. #else
  58. #define FETCHSYM FetchSym
  59. #endif
  60. LOCAL char chErr = 'L'; /* Error message prefix */
  61. /*
  62. * LOCAL FUNCTION PROTOTYPES
  63. */
  64. LOCAL void cdecl NEAR ErrSub(MSGTYPE msg, WORD fWarn, va_list pArgList);
  65. LOCAL void vFmtPrint(char *fmt, va_list pArgList);
  66. /*** ChkInput - check input file for I/O errors
  67. *
  68. * Purpose:
  69. * Check if there were any I/O errors on input file.
  70. *
  71. * Input:
  72. * No explicit value is passed. The global input file bsInput is
  73. * used.
  74. *
  75. * Output:
  76. * If everything is OK function returns, otherwise it calls Fatal
  77. * with appropriate error message.
  78. *
  79. * Exceptions:
  80. * None.
  81. *
  82. * Notes:
  83. * None.
  84. *
  85. *************************************************************************/
  86. void ChkInput(void)
  87. {
  88. if (feof(bsInput))
  89. Fatal(ER_eofobj);
  90. else if (ferror(bsInput))
  91. Fatal(ER_ioerr, strerror(errno));
  92. }
  93. // Comment : GetMsg and __NMSG_TEXT are generated by MKMSG [jp]
  94. /*** ErrPrefix - write error message prefix
  95. *
  96. * Purpose:
  97. * Write out error message prefix. If we are parsinf .DEF file or reading
  98. * .OBJ files then the error message prefix takes form "<filename> : "
  99. * otherwise this is "LINK : ".
  100. *
  101. * Input:
  102. * No explicit value is passed.
  103. *
  104. * Output:
  105. * No explicit value is returned.
  106. *
  107. * Exceptions:
  108. * None.
  109. *
  110. * Notes:
  111. * None.
  112. *
  113. *************************************************************************/
  114. void ErrPrefix(void)
  115. {
  116. DisplayBanner();
  117. if (fDrivePass || yylineno > 0)
  118. OutFileCur(bsErr);
  119. else
  120. FmtPrint(lnknam);
  121. FmtPrint(" : ");
  122. }
  123. #pragma check_stack(on)
  124. /*** OutFileCur - write out current input file name
  125. *
  126. * Purpose:
  127. * Write out current input file name. Used by error message functions.
  128. * File name is written in the following formats:
  129. * <filename>(nnn)
  130. * <filename>(<modulename>)
  131. * <filename>
  132. *
  133. * Input:
  134. * bs - file to which current input file name is written
  135. *
  136. * Output:
  137. * No explicit value is returned.
  138. *
  139. * Exceptions:
  140. * None.
  141. *
  142. * Notes:
  143. * None.
  144. *
  145. *************************************************************************/
  146. void OutFileCur(BSTYPE bs)
  147. {
  148. APROPFILEPTR apropFile; /* Pointer to file property cell */
  149. AHTEPTR ahte; /* Pointer symbol name */
  150. BSTYPE bsTmp; /* Temporary file pointer */
  151. SBTYPE fileName; /* File name buffer */
  152. SBTYPE moduleName; /* Object module name */
  153. int n; /* String length counter */
  154. #if OSEGEXE
  155. if (yylineno > 0)
  156. {
  157. apropFile = (APROPFILEPTR) FETCHSYM(rhteDeffile,FALSE);
  158. ahte = GetHte(rhteDeffile);
  159. }
  160. else
  161. #endif
  162. {
  163. apropFile = (APROPFILEPTR ) FETCHSYM(vrpropFile,FALSE);
  164. ahte = GetHte(vrpropFile);
  165. }
  166. bsTmp = bsErr;
  167. bsErr = bs;
  168. // Copy file name
  169. n = (ahte->cch[0] < sizeof(fileName) - 1) ? ahte->cch[0] : sizeof(fileName) - 1;
  170. FMEMCPY((char FAR *) fileName, &ahte->cch[1], n);
  171. fileName[n] = '\0';
  172. if (yylineno > 0)
  173. FmtPrint("%s(%d)", fileName, yylineno);
  174. else if (apropFile->af_rMod)
  175. {
  176. // Get object module name
  177. ahte = (AHTEPTR ) FETCHSYM(apropFile->af_rMod,FALSE);
  178. while(ahte->attr != ATTRNIL)
  179. ahte = (AHTEPTR ) FETCHSYM(ahte->rhteNext,FALSE);
  180. n = (ahte->cch[0] < sizeof(moduleName) - 1) ? ahte->cch[0] : sizeof(moduleName) - 1;
  181. FMEMCPY((char FAR *) moduleName, &ahte->cch[1], n);
  182. moduleName[n] = '\0';
  183. FmtPrint("%s(%s)", fileName, moduleName);
  184. }
  185. else
  186. FmtPrint("%s", fileName);
  187. bsErr = bsTmp;
  188. }
  189. #pragma check_stack(off)
  190. #if (QCLINK OR OSEGEXE) AND NOT EXE386
  191. typedef int (cdecl FAR * FARFPTYPE)(char FAR *buf);
  192. /* Far function pointer type */
  193. extern FARFPTYPE FAR *pfQTab; /* Table of addresses */
  194. #endif
  195. /*** vFmtPrint - print formated message
  196. *
  197. * Purpose:
  198. * Print on bsErr formated error or warning message.
  199. * Check for any I/O errors.
  200. *
  201. * Input:
  202. * fmt - error message format string
  203. * pArgList - pointer to variable number of parameters desrcibing error message
  204. * bsErr - error file - global variable
  205. * bsLst - listing file - global variable
  206. *
  207. * Output:
  208. * No explicit value is returned.
  209. *
  210. * Exceptions:
  211. * I/O errors. If error detected and stdout is an error file then silently
  212. * exit to system with return code 4 (something must be terribly wrong
  213. * if stdout is not working). If we are writing to listing file and
  214. * error was detected then close listing file and notify user.
  215. *
  216. * Notes:
  217. * This function handles output to QC enviroment.
  218. *
  219. *************************************************************************/
  220. LOCAL void vFmtPrint(char *fmt, va_list pArgList)
  221. {
  222. #if WIN_3
  223. char buf[512];
  224. vsprintf(buf, fmt, pArgList);
  225. ErrMsgWin(buf);
  226. #if DEBUG_WIN2
  227. OutputDebugString((char far*)"\r\nDebS: ");
  228. OutputDebugString((char far*)buf);
  229. #endif
  230. #else
  231. #if (QCLINK) AND NOT EXE386
  232. SBTYPE buf;
  233. if (fZ1)
  234. {
  235. // Output via QC call-back
  236. vsprintf(buf, fmt, pArgList);
  237. (*pfQTab[0])((char far *) buf);
  238. }
  239. else
  240. #endif
  241. {
  242. vfprintf(bsErr, fmt, pArgList);
  243. if (ferror(bsErr))
  244. {
  245. if (bsErr == stdout)
  246. {
  247. #if USE_REAL
  248. RealMemExit();
  249. #endif
  250. exit(4);
  251. }
  252. else if (bsErr == bsLst)
  253. {
  254. fclose(bsLst);
  255. fLstFileOpen = FALSE;
  256. bsErr = stdout;
  257. }
  258. ExitCode = 4;
  259. Fatal(ER_spclst);
  260. }
  261. fflush(bsErr);
  262. }
  263. #endif // WIN_3
  264. }
  265. /*** FmtPrint - print formated message
  266. *
  267. * Purpose:
  268. * Print on bsErr formated error or warning message.
  269. * Check for any I/O errors.
  270. *
  271. * Input:
  272. * fmt - error message format string
  273. * ... - variable number of parameters desrcibing error message
  274. *
  275. * Output:
  276. * No explicit value is returned.
  277. *
  278. * Exceptions:
  279. * I/O errors.
  280. *
  281. * Notes:
  282. * The actual job is done by the vFmtPrint.
  283. *
  284. *************************************************************************/
  285. void cdecl FmtPrint(char *fmt, ...)
  286. {
  287. va_list pArgList;
  288. va_start(pArgList, fmt);
  289. vFmtPrint(fmt, pArgList);
  290. }
  291. #if OSMSDOS AND NOT WIN_3
  292. /*
  293. * PromptStd : Standard prompt routine
  294. *
  295. * Display a warning message and prompt, with optional arguments.
  296. * Optionally read a response into a given buffer. If the given
  297. * buffer is null, get a yes/no response with <ENTER> being yes.
  298. *
  299. * Returns:
  300. * TRUE if yes or response read.
  301. * FALSE if no.
  302. */
  303. int cdecl PromptStd (sbNew,msg,msgparm,pmt,pmtparm)
  304. BYTE *sbNew; /* Buffer for response */
  305. MSGTYPE msg; /* Error message */
  306. int msgparm; /* Message parameter */
  307. MSGTYPE pmt; /* Prompt */
  308. int pmtparm; /* Prompt parameter */
  309. {
  310. register BYTE *p;
  311. int ch;
  312. int n;
  313. if(msg)
  314. OutWarn(msg, msgparm);
  315. if(!pmt)
  316. return(TRUE);
  317. fprintf(stderr,GetMsg(pmt),pmtparm);
  318. fflush(stderr); /* Flush stderr */
  319. #if CPU286
  320. flskbd(); /* Flush DOS keyboard buffer */
  321. #endif
  322. fflush(stdin); /* Flush console input */
  323. if(sbNew != NULL)
  324. {
  325. /* Read response */
  326. for(p = &sbNew[1], n = 0;
  327. (ch = fgetc(stdin)) != '\n' && ch != EOF && n < sizeof(SBTYPE); )
  328. {
  329. #if CRLF
  330. if(ch == '\r')
  331. continue;
  332. #endif
  333. *p++ = (BYTE) ch;
  334. n++;
  335. }
  336. sbNew[0] = (BYTE) n;
  337. return(TRUE);
  338. }
  339. #if CRLF
  340. if(fgetc(stdin) != '\r')
  341. return(FALSE);
  342. #endif
  343. if(fgetc(stdin) != '\n')
  344. return(FALSE);
  345. return(TRUE);
  346. }
  347. #endif /* OSMSDOS */
  348. /*
  349. * CputcStd : standard console character output routine.
  350. * Call fputc to stdout. Will be called through pfCputc.
  351. */
  352. void CputcStd (ch)
  353. int ch;
  354. {
  355. putc(ch,stdout);
  356. if (ferror(stdout))
  357. exit(4);
  358. }
  359. /*
  360. * CputsStd : standard console string output routine
  361. * Call fputs to stdout. Will be called through pfCputs.
  362. */
  363. void CputsStd (str)
  364. char *str;
  365. {
  366. fputs(str,stdout);
  367. if (ferror(stdout))
  368. {
  369. #if USE_REAL
  370. RealMemExit();
  371. #endif
  372. exit(4);
  373. }
  374. fflush(stdout);
  375. }
  376. /*** ErrSub - write out nonfatal error message
  377. *
  378. * Purpose:
  379. * Fromat and write out nonfatal error message. If error message number
  380. * is equal to zero then we treat it as a prompt.
  381. *
  382. * Input:
  383. * msg - error message number
  384. * fWarn - TRUE if this warnnig
  385. * ... - variable number of parameters for message
  386. * bsErr - error file - global variable
  387. * bsLst - listing file - global variable
  388. *
  389. * Output:
  390. * No explicit value is returned.
  391. *
  392. * Exceptions:
  393. * None.
  394. *
  395. * Notes:
  396. * None.
  397. *
  398. *************************************************************************/
  399. LOCAL void cdecl NEAR ErrSub(MSGTYPE msg, WORD fWarn, va_list pArgList)
  400. {
  401. if (fLstFileOpen && bsErr == bsLst && vgsnLineNosPrev)
  402. { /* If we've listed line numbers */
  403. NEWLINE(bsErr); /* Newline */
  404. vgsnLineNosPrev = 0; /* Reset */
  405. }
  406. if (msg)
  407. {
  408. /* If there is any message to print */
  409. #if WIN_3
  410. if(fWarn)
  411. fSeverity=SEV_WARNING;
  412. else
  413. fSeverity=SEV_ERROR;
  414. #endif
  415. #if MSGMOD AND NOT WIN_3
  416. if (msg >= 1000)
  417. {
  418. #endif
  419. /* Error or warning */
  420. ErrPrefix();
  421. #if MSGMOD
  422. FmtPrint("%s %c%04d: ",
  423. fWarn ? __NMSG_TEXT(N_warning) : __NMSG_TEXT(N_error),
  424. (int) chErr, msg);
  425. #else
  426. FmtPrint("%s: ",fWarn ? "warning" : "error");
  427. #endif
  428. vFmtPrint(GetMsg(msg), pArgList);
  429. #if NOT WIN_3
  430. #if QCLINK
  431. if (fZ1)
  432. FmtPrint("\n");
  433. else
  434. #endif
  435. NEWLINE(bsErr);
  436. #else
  437. FmtPrint("\r\n");
  438. // for the second part of the message
  439. fSeverity = SEV_WARNING;
  440. #endif
  441. if (fDrivePass && !fWarn
  442. #if MSGMOD
  443. && (msg >= 2005 && msg < 2022) || msg == 1101
  444. #endif
  445. )
  446. FmtPrint("%s: %lx %s: %02x\r\n",
  447. __NMSG_TEXT(N_pos),ftell(bsInput),
  448. __NMSG_TEXT(N_rectyp),rect & 0xff);
  449. #if MSGMOD AND NOT WIN_3
  450. }
  451. else
  452. {
  453. /* Prompt */
  454. #if QCLINK
  455. if (fZ1)
  456. (*pfPrompt)(NULL, msg, (int) pArgList, 0, 0);
  457. else
  458. {
  459. #endif
  460. vFmtPrint(GetMsg(msg), pArgList);
  461. NEWLINE(bsErr);
  462. #if QCLINK
  463. }
  464. #endif
  465. }
  466. #endif
  467. }
  468. }
  469. /*** OutError - write out nonfatal error message
  470. *
  471. * Purpose:
  472. * Top level function called when error message has to be displayed.
  473. * Bumps the error counter and calls ErrSub to do the job.
  474. *
  475. * Input:
  476. * msg - error message number
  477. * ... - variable number of error parameters
  478. *
  479. * Output:
  480. * No explicit value is returned. Global error counter cErrors is
  481. * incremented.
  482. *
  483. * Exceptions:
  484. * None.
  485. *
  486. * Notes:
  487. * None.
  488. *
  489. *************************************************************************/
  490. void cdecl OutError(MSGTYPE msg, ...)
  491. {
  492. va_list pArgList;
  493. va_start(pArgList, msg);
  494. ++cErrors; /* Increment error count */
  495. ErrSub(msg, FALSE, pArgList);
  496. }
  497. /*** OutWarn - write out warning message
  498. *
  499. * Purpose:
  500. * Top level function called when warning message has to be displayed.
  501. * Calls ErrSub to do the job.
  502. *
  503. * Input:
  504. * msg - error message number
  505. * ... - variable number of error parameters
  506. *
  507. * Output:
  508. * No explicit value is returned.
  509. * incremented.
  510. *
  511. * Exceptions:
  512. * None.
  513. *
  514. * Notes:
  515. * None.
  516. *
  517. *************************************************************************/
  518. void cdecl OutWarn (MSGTYPE msg, ...)
  519. {
  520. va_list pArgList;
  521. DEBUGW("\r\nOutWarn entered",0);
  522. va_start(pArgList, msg);
  523. ErrSub(msg, TRUE, pArgList);
  524. }
  525. /*** KillRunFile - delete .EXE file
  526. *
  527. * Purpose:
  528. * Delete the .EXE file created by the linker.
  529. *
  530. * Input:
  531. * No explicit value is passed.
  532. * bsRunfile - output file handle - global variable.
  533. * psbRun - output file name - global variable.
  534. *
  535. * Output:
  536. * No explicit value is returned.
  537. *
  538. * Exceptions:
  539. * None.
  540. *
  541. * Notes:
  542. * None.
  543. *
  544. *************************************************************************/
  545. void KillRunfile(void)
  546. {
  547. if (bsRunfile != NULL)
  548. {
  549. CloseFile(bsRunfile);
  550. _unlink(&psbRun[1]);
  551. }
  552. }
  553. /*** Fatal - write out fatal error message
  554. *
  555. * Purpose:
  556. * Format and write out fatal error message. Terminate linker.
  557. *
  558. * Input:
  559. * msg - error message number
  560. * ... - variable number of message parameters
  561. * bsLst - listing file - global variable
  562. *
  563. * Output:
  564. * No explicit value is returned. Linker terminates.
  565. *
  566. * Exceptions:
  567. * None.
  568. *
  569. * Notes:
  570. * None.
  571. *
  572. *************************************************************************/
  573. void cdecl Fatal (MSGTYPE msg, ...)
  574. {
  575. static WORD cInvoked =0;
  576. va_list pArgList;
  577. va_start(pArgList, msg); /* Get start of argument list */
  578. if (++cInvoked > 1) // Fatal during Fatal
  579. {
  580. #if USE_REAL
  581. RealMemExit();
  582. #endif
  583. if (ExitCode)
  584. EXIT(ExitCode);
  585. else
  586. EXIT(2); /* Program error */
  587. }
  588. /* If msg is nonzero then print a message */
  589. if (msg)
  590. {
  591. if (fLstFileOpen)
  592. fflush(bsLst);
  593. ErrPrefix();
  594. #if MSGMOD
  595. FmtPrint("%s %c%04d: ", __NMSG_TEXT(N_fatal), chErr, msg);
  596. #else
  597. FmtPrint("fatal error: ");
  598. #endif
  599. vFmtPrint(GetMsg(msg), pArgList);
  600. #if WIN_3
  601. fSeverity = SEV_ERROR; // Send as error to QCwin
  602. FmtPrint("\r\n");
  603. #else
  604. NEWLINE(stderr);
  605. #endif
  606. if(fDrivePass && ftell(bsInput)
  607. #if MSGMOD
  608. && msg >= 2005 && msg < 2022 || msg == 1101
  609. #endif
  610. )
  611. FmtPrint("%s: %lx %s: %02x\r\n",
  612. __NMSG_TEXT(N_pos),ftell(bsInput),
  613. __NMSG_TEXT(N_rectyp),rect & 0xff);
  614. }
  615. KillRunfile();
  616. if (fLstFileOpen) fclose(bsLst);
  617. #if OWNSTDIO
  618. FlsStdio();
  619. #endif
  620. // If someone else assigned the exit code, use it. Otherwise,
  621. // assume program error.
  622. if (ExitCode)
  623. EXIT(ExitCode);
  624. else
  625. EXIT(2); /* Program error */
  626. }
  627. /*** CtrlC - display Ctrl-C error message and die
  628. *
  629. * Purpose:
  630. * Do minimal work required to display error message and die.
  631. *
  632. * Input:
  633. * No explicit value is passed.
  634. *
  635. * Output:
  636. * No explicit value is returned.
  637. *
  638. * Exceptions:
  639. * None.
  640. *
  641. * Notes:
  642. * This function doesn't return.
  643. *
  644. *************************************************************************/
  645. void CtrlC(void)
  646. {
  647. #if USE_REAL
  648. RealMemExit();
  649. #endif
  650. #ifdef OS2
  651. if (_osmode == OS2_MODE)
  652. fputs("\r\n", stdout);
  653. #endif
  654. #if DOSEXTENDER AND NOT WIN_NT
  655. if (!_fDosExt)
  656. {
  657. #endif
  658. if (fLstFileOpen)
  659. fflush(bsLst);
  660. ErrPrefix();
  661. FmtPrint("%s %c%04d: %s", __NMSG_TEXT(N_fatal), chErr, ER_intrpt, GetMsg(ER_intrpt));
  662. KillRunfile();
  663. if (fLstFileOpen)
  664. fclose(bsLst);
  665. #if OWNSTDIO
  666. FlsStdio();
  667. #endif
  668. EXIT(4);
  669. #if DOSEXTENDER AND NOT WIN_NT
  670. }
  671. else
  672. _exit(4);
  673. #endif
  674. }