msdsys.c
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:77k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. /*********************************************************************
  2.  * Microsoft Diagnostics Version 2.0
  3.  *
  4.  * A diagnostic utility to detect as much useful information about a
  5.  *   customer's computer system as is possible.
  6.  *
  7.  * Microsoft Diagnostics:  We detect the World.
  8.  *
  9.  * MSDSYS.C - Source file for system related code (ie file I/O).
  10.  ********************************************************************/
  11. /* Include Files */
  12. #include "msd.h"
  13. /********************************************************************
  14.  * OpenFile - Opens a file and provides appropriate error handling.
  15.  *
  16.  * pszFilename - Name of file
  17.  * pszMode     - Mode to open the file.
  18.  * fShowError  - Displays errors when TRUE.
  19.  *
  20.  * Returns: FILE handle, or NULL if an error condition occured.
  21.  ********************************************************************/
  22. FILE * OpenFile (PSZ pszFilename, PSZ pszMode, BOOL fShowError)
  23. {
  24.   FILE *fp;           /* Local storage for the file pointer */
  25.   /* Open the file */
  26.   fp = fopen (pszFilename, pszMode);
  27.   /* Give appropriate error message, if necessary */
  28.   if (fShowError && (fp == NULL || fCriticalError))
  29.     {
  30.       fCriticalError = FALSE;
  31.       ShowError (ERR_OK_BUTTON, pszErrorOpening, pszFilename, 
  32.                  _strerror (NULL));
  33.       return (NULL);
  34.     }
  35.   /* If all went well, return the file pointer to the calling routine */
  36.   return (fp);
  37. }
  38. /********************************************************************
  39.  * CloseFile - Closes a file and provides appropriate error handling.
  40.  *
  41.  * fp - File handle to close
  42.  *
  43.  * Returns: TRUE if an error occured.
  44.  ********************************************************************/
  45. BOOL CloseFile (FILE *fp)
  46. {
  47.   WORD wReturnValue;  /* Return value from fclose */
  48.   /* Close the file */
  49.   wReturnValue = fclose (fp);
  50.   /* Give appropriate error message, if necessary */
  51.   if (wReturnValue == EOF)
  52.     {
  53.       fCriticalError = FALSE;
  54.       ShowError (ERR_OK_BUTTON, pszErrorClosing, NULL, _strerror (NULL));
  55.       return (TRUE);
  56.     }
  57.   return (FALSE);
  58. }
  59. /**********************************************************************
  60.  * CreateTempFile - Uses a DOS 3+ call to create a unique file
  61.  *
  62.  * pszPathname - Path to where the temp file needs to go.
  63.  *
  64.  * Returns: Error number:
  65.  *          03 - Path not found.
  66.  *          04 - No more handles.
  67.  *          05 - Access denied.
  68.  **********************************************************************/
  69. WORD CreateTempFile (PSZ pszPathname)
  70. {
  71.   union REGS inregs, outregs;   /* Register values for int86x */
  72.   struct SREGS sregs;           /* Segment register values */
  73.   CHAR FAR * fpszPathname = (CHAR FAR *) pszPathname;
  74.   inregs.h.ah = 0x5A;
  75.   inregs.x.cx = 0;
  76.   sregs.ds    = (WORD) FP_SEG (fpszPathname);
  77.   inregs.x.dx = (WORD) FP_OFF (fpszPathname);
  78.   int86x (0x21, &inregs, &outregs, &sregs);
  79.   if (outregs.x.cflag)
  80.     return (outregs.x.ax);
  81.   else
  82.     return (0);
  83. }
  84. /**********************************************************************
  85.  * DeleteFile - Deletes file specified by pszFilename
  86.  *
  87.  * pszFilename - File to delete
  88.  *
  89.  * Returns: Error number:
  90.  *          02 - File not found.
  91.  *          03 - Path not found.
  92.  *          05 - Access denied.
  93.  **********************************************************************/
  94. WORD DeleteFile (PSZ pszPathname)
  95. {
  96.   union REGS inregs, outregs;   /* Register values for intdos */
  97.   struct SREGS sregs;           /* Segment register values */
  98.   CHAR FAR * fpszPathname = (CHAR FAR *) pszPathname;
  99.   inregs.h.ah = 0x41;
  100.   sregs.ds    = (WORD) FP_SEG (fpszPathname);
  101.   inregs.x.dx = (WORD) FP_OFF (fpszPathname);
  102.   int86x (0x21, &inregs, &outregs, &sregs);
  103.   if (outregs.x.cflag)
  104.     return (outregs.x.ax);
  105.   else
  106.     return (0);
  107. }
  108. /**********************************************************************
  109.  * RenameFile - Renames a file.
  110.  *
  111.  * pszPathname1 - File to rename.
  112.  * pszPathname2 - New filename.
  113.  *
  114.  * Returns: Error number:
  115.  *          02 - File not found.
  116.  *          03 - Path not found.
  117.  *          05 - Access denied.
  118.  *          17 - (11H) Not the same device.
  119.  **********************************************************************/
  120. WORD RenameFile (PSZ pszPathname1, PSZ pszPathname2)
  121. {
  122.   union REGS inregs, outregs;   /* Register values for intdos */
  123.   struct SREGS sregs;           /* Segment register values */
  124.   CHAR FAR * fpszPathname1 = (CHAR FAR *) pszPathname1;
  125.   CHAR FAR * fpszPathname2 = (CHAR FAR *) pszPathname2;
  126.   inregs.h.ah = 0x56;
  127.   sregs.ds    = (WORD) FP_SEG (fpszPathname1);
  128.   inregs.x.dx = (WORD) FP_OFF (fpszPathname1);
  129.   sregs.es    = (WORD) FP_SEG (fpszPathname2);
  130.   inregs.x.di = (WORD) FP_OFF (fpszPathname2);
  131.   int86x (0x21, &inregs, &outregs, &sregs);
  132.   if (outregs.x.cflag)
  133.     return (outregs.x.ax);
  134.   else
  135.     return (0);
  136. }
  137. WORD wNmbrFound = 0;
  138. /*********************************************************************
  139.  * FindFile - Finds all of the pszFilename files on the system.
  140.  *
  141.  * pszFilename   - Filename to find.
  142.  *
  143.  * pszPathname   - Path to start searching from (NULL if it's to be
  144.  *                 ignored).
  145.  *
  146.  * fSearchFlags  - SEARCH_FLOPPIES          Search floppies.
  147.  *                 SEARCH_LOCAL_DRIVES      Search local hard disks.
  148.  *                 SEARCH_NET_DRIVES        Search net drives (and
  149.  *                                          all other drives).
  150.  *                 SEARCH_ROOT              Search the root directory.
  151.  *                 RECURSE_INTO_SUB_DIRS    Search recursively into
  152.  *                                          subdirectories.
  153.  *
  154.  *                 Only one of the following should be specified at
  155.  *                   one time:
  156.  *                 SEARCH_LANMAN_ROOT       Searches in the LANMAN
  157.  *                                          root directory.
  158.  *                 SEARCH_WINDIR            Uses the "windir="
  159.  *                                          environment variable.
  160.  *                 SEARCH_BOOT_DRIVE        Search just the boot drive.
  161.  *
  162.  * chDriveLetter - If fSearchFlags does not specify the drive type(s)
  163.  *                 to search, this contains the drive letter to
  164.  *                 search.  ('' to search current drive).
  165.  *
  166.  * Returns:  Pointer to an array of strings to pszFilename files, the
  167.  *           last pointer is a NULL pointer.  If pszFilename could
  168.  *           not be found, or an error occured, the first pointer is a
  169.  *           NULL.
  170.  *********************************************************************/
  171. FILE_INFO FAR *FindFile (PSZ  pszFilename,
  172.                          PSZ  pszPathname,
  173.                          BOOL fSearchFlags,
  174.                          CHAR chDriveLetter)
  175. {
  176.   CHAR chCurrentPath[_MAX_PATH + 1];  /* Stores current drive & directory  */
  177.   WORD wCurrentDrive;                 /* Stores the current drive number   */
  178.   WORD i;                             /* Looping variable                  */
  179.   DISK_STRUCT *pDisk = NULL;          /* Pointer to disk drive info        */
  180.                                       /*   structure                       */
  181.   OS_VERSION_STRUCT *pOsVer = NULL;   /* Pointer to DOS info structure     */
  182.   BOOL fReturnValue = FALSE;          /* Stores the return value from      */
  183.                                       /*   fuctions                        */
  184.   FILE_INFO FAR *pFileInfo = NULL;    /* Pointer to file info linked list  */
  185.   FILE_INFO FAR *pfi = NULL;          /* Another pointer to file info list */
  186.                                       /*   (this one is changed by the     */
  187.                                       /*   called routines).               */
  188.   /* Save the current drive and directory */
  189.   wCurrentDrive = _getdrive();
  190.   _getdcwd (wCurrentDrive, chCurrentPath, _MAX_PATH);
  191.   /* Allocate enough room for the find file info */
  192.   pFileInfo = _fmalloc (sizeof (FILE_INFO));
  193.   if (pFileInfo == NULL)
  194.     {
  195.       OutOfMemory();
  196.       return (NULL);
  197.     }
  198.   pfi = pFileInfo;
  199.   /* Set the first pointer to null, to show that */
  200.   /*   this is the last on the list.             */
  201.   pFileInfo->fpNextFileInfo = NULL;
  202.   /* Get the disk and operating system structures */
  203.   fReturnValue = GetFindFileInfo (&pDisk, &pOsVer, fSearchFlags);
  204.   if (fReturnValue)
  205.     {
  206.       FreeFileInfo (pFileInfo);
  207.       return (NULL);
  208.     }
  209.   /* Zero out the counter for files found */
  210.   wNmbrFound = 0;
  211.   /* Change to the appropriate drive and directory if necessary */
  212.   if (pszPathname != NULL)
  213.     {
  214.       /* Check to see if a drive was passed to us */
  215.       if (pszPathname[1] == ':')
  216.         {
  217.           WORD wDrive = toupper (pszPathname[0]) - 'A' + 1;
  218.           if (_chdrive (wDrive))
  219.             {
  220.               MessageBox ("Drive does not exist", pszPathname, NULL, MB_OK | 0x8000);
  221.               return (NULL);
  222.             }
  223.           if (chdir (&pszPathname[2]))
  224.             {
  225.               MessageBox (pszPathNotThere, pszPathname, NULL, MB_OK | 0x8000);
  226.               return (NULL);
  227.             }
  228.         }
  229.       else
  230.         if (chdir (pszPathname))
  231.           {
  232.             MessageBox (pszPathNotThere, pszPathname, NULL, MB_OK | 0x8000);
  233.             return (NULL);
  234.           }
  235.     }
  236.   /* Boot drive search */
  237.   if (fSearchFlags & SEARCH_BOOT_DRIVE)
  238.     {
  239.       FindOnBootDrive (&pfi,
  240.                        pDisk,
  241.                        pOsVer,
  242.                        pszFilename,
  243.                        fSearchFlags);
  244.     }
  245.   else if (fSearchFlags & SEARCH_WINDIR)
  246.     {
  247.       /* Find the "windir=" environment variable */
  248.       for (i = 0;
  249.            environ[i][0] != '' && memcmp ("windir=", environ[i], 7) != 0;
  250.            ++i)
  251.         ;
  252.       /* If found, put the fully qualified path into chWinDir */
  253.       if (environ[i][0] == 'w')
  254.         {
  255.           /* Change to the drive and directory of the file */
  256.           chDriveLetter = environ[i][7];
  257.           chdir (&environ[i][9]);
  258.           /* Find the file */
  259.           FindFileOnDrive (&pfi,
  260.                            pszFilename,
  261.                            fSearchFlags,
  262.                            chDriveLetter);
  263.         }
  264.       else
  265.         {
  266.           /* Free up pFileInfo */
  267.           _ffree (pFileInfo);
  268.           /* Set the flags for finding the windows file the hard way */
  269.           fSearchFlags = SEARCH_LOCAL_DRIVES   |
  270.                          SEARCH_ROOT           |
  271.                          RECURSE_INTO_SUB_DIRS;
  272.           /* Find the file */
  273.           pFileInfo = FindFile (pszFilename, pszPathname,
  274.                                 fSearchFlags, chDriveLetter);
  275.         }
  276.     }
  277.   else if (fSearchFlags & SEARCH_LANMAN_ROOT)
  278.     {
  279.       unsigned short int err=0, ta=0;
  280.       struct wksta_info_0 *wksta0;
  281.       char wkstabuf[BUFSIZ];
  282.       CHAR chBuffer[_MAX_PATH + 1];
  283.       /* Get the LANMAN root */
  284.       err = NetWkstaGetInfo (NULL, 0, wkstabuf, BUFSIZ, &ta);
  285.       if (err == 0)
  286.         {
  287.           wksta0 = (struct wksta_info_0 *) wkstabuf;
  288.           _fmemcpy (chBuffer, wksta0->wki0_root, _MAX_PATH);
  289.           /* Change to the drive and directory of the file */
  290.           chDriveLetter = chBuffer[0];
  291.           chdir (&chBuffer[2]);
  292.           /* Find the file */
  293.           FindFileOnDrive (&pfi,
  294.                            pszFilename,
  295.                            fSearchFlags,
  296.                            chDriveLetter);
  297.         }
  298.       else
  299.         {
  300.           /* Free up pFileInfo */
  301.           _ffree (pFileInfo);
  302.           /* Set the flags for finding the LANMAN file the hard way */
  303.           fSearchFlags = SEARCH_LOCAL_DRIVES   |
  304.                          SEARCH_ROOT           |
  305.                          RECURSE_INTO_SUB_DIRS;
  306.           /* Find the file */
  307.           pFileInfo = FindFile (pszFilename, pszPathname,
  308.                                 fSearchFlags, chDriveLetter);
  309.         }
  310.     }
  311.   else if ((fSearchFlags & (SEARCH_FLOPPIES     |
  312.                             SEARCH_LOCAL_DRIVES |
  313.                             SEARCH_NET_DRIVES   |
  314.                             SEARCH_BOOT_DRIVE)) == 0)
  315.     {
  316.       /* Single drive search */
  317.       FindFileOnDrive (&pfi,
  318.                        pszFilename,
  319.                        fSearchFlags,
  320.                        chDriveLetter);
  321.     }
  322.   else
  323.     {
  324.       /* Search 'em all */
  325.       for (i = 0; i < pDisk->wNmbrDrives; ++i)
  326.         {
  327.           /* Floppy Search */
  328.           if ((fSearchFlags & SEARCH_FLOPPIES) &&
  329.               (pDisk->asdi[i].wDriveType == DISK_FLOPPY_DRIVE          ||
  330.                pDisk->asdi[i].wDriveType == DISK_525_360K              ||
  331.                pDisk->asdi[i].wDriveType == DISK_525_12M               ||
  332.                pDisk->asdi[i].wDriveType == DISK_35_720K               ||
  333.                pDisk->asdi[i].wDriveType == DISK_SINGLE_DENSITY_8_INCH ||
  334.                pDisk->asdi[i].wDriveType == DISK_DOUBLE_DENSITY_8_INCH ||
  335.                pDisk->asdi[i].wDriveType == DISK_35_144M               ||
  336.                pDisk->asdi[i].wDriveType == DISK_OPTICAL_DISK          ||
  337.                pDisk->asdi[i].wDriveType == DISK_35_288M))
  338.             {
  339.               FindFileOnDrive (&pfi,
  340.                                pszFilename,
  341.                                fSearchFlags,
  342.                                pDisk->asdi[i].chDriveLetter);
  343.             }
  344.           /* Local drive search */
  345.           if ((fSearchFlags & SEARCH_LOCAL_DRIVES) &&
  346.               (pDisk->asdi[i].wDriveType == DISK_FIXED_DISK   ||
  347.                pDisk->asdi[i].wDriveType == DISK_RAM_DISK     ||
  348.                pDisk->asdi[i].wDriveType == DISK_CD_ROM_DRIVE ||
  349.                pDisk->asdi[i].wDriveType == DISK_SUBST_DRIVE  ||
  350.                pDisk->asdi[i].wDriveType == DISK_ASSIGN_DRIVE))
  351.             {
  352.               FindFileOnDrive (&pfi,
  353.                                pszFilename,
  354.                                fSearchFlags,
  355.                                pDisk->asdi[i].chDriveLetter);
  356.             }
  357.           /* Remote/Net drive search */
  358.           if ((fSearchFlags & SEARCH_NET_DRIVES) &&
  359.               pDisk->asdi[i].wDriveType == DISK_REMOTE_DRIVE)
  360.             {
  361.               FindFileOnDrive (&pfi,
  362.                                pszFilename,
  363.                                fSearchFlags,
  364.                                pDisk->asdi[i].chDriveLetter);
  365.             }
  366.         }
  367.     }
  368.   /* Restore the current drive and directory */
  369.   _chdrive (wCurrentDrive);
  370.   chdir (chCurrentPath);
  371.   /* Free up the disk and operating system info */
  372.   free (pDisk);
  373.   free (pOsVer);
  374.   return (pFileInfo);
  375. }
  376. /*********************************************************************
  377.  * FindOnBootDrive - Finds a particular file on the boot drive.  If
  378.  *                   the operating system does not have the ability
  379.  *                   to return the boot drive, it will check the first
  380.  *                   hard disk, the first floppy, then all other
  381.  *                   drives on the system (based on the flags set in
  382.  *                   fSearchFlags, of course).
  383.  *
  384.  * ppFileInfo   - Pointer to file info structure's pointer.
  385.  * pszFilename  - Filename to search for.
  386.  * fSearchFlags - Flags to control the search.
  387.  *
  388.  * Returns:  TRUE if an error occured.
  389.  *********************************************************************/
  390. BOOL FindOnBootDrive (FILE_INFO FAR * FAR *ppFileInfo,
  391.                       DISK_STRUCT         *pDisk,
  392.                       OS_VERSION_STRUCT   *pOsVer,
  393.                       PSZ                 pszFilename,
  394.                       BOOL                fSearchFlags)
  395. {
  396.   BOOL fSkipFirstFloppy   = TRUE;  /* Allows us to skip drives */
  397.   BOOL fSkipFirstHardDisk = TRUE;  /*   we already checked     */
  398.   /* Check to see if DOS can tell us it's boot drive */
  399.   if (pOsVer->wDosMajor >= 4)
  400.     {
  401.       /* Set the flags for the appropriate search */
  402.       fSearchFlags = fSearchFlags | SEARCH_ROOT;
  403.       /* Find it */
  404.       FindFileOnDrive (ppFileInfo,
  405.                        pszFilename,
  406.                        fSearchFlags,
  407.                        pOsVer->chDosBootDrive);
  408.     }
  409.   else
  410.     {
  411.       WORD i;   /* Looping variable */
  412.       /* We have to hunt for a suitable boot drive */
  413.       /* Set the flags for the appropriate search */
  414.       fSearchFlags = fSearchFlags          |
  415.                      SEARCH_FLOPPIES       |
  416.                      SEARCH_LOCAL_DRIVES   |
  417.                      SEARCH_ROOT;
  418.       /* Check the first hard disk */
  419.       if (fSearchFlags & SEARCH_LOCAL_DRIVES)
  420.         {
  421.           for (i = 0; i < pDisk->wNmbrDrives; ++i)
  422.             {
  423.               if (pDisk->asdi[i].wDriveType == DISK_FIXED_DISK   ||
  424.                   pDisk->asdi[i].wDriveType == DISK_RAM_DISK     ||
  425.                   pDisk->asdi[i].wDriveType == DISK_CD_ROM_DRIVE ||
  426.                   pDisk->asdi[i].wDriveType == DISK_SUBST_DRIVE  ||
  427.                   pDisk->asdi[i].wDriveType == DISK_ASSIGN_DRIVE)
  428.                 {
  429.                   FindFileOnDrive (ppFileInfo,
  430.                                    pszFilename,
  431.                                    fSearchFlags,
  432.                                    pDisk->asdi[i].chDriveLetter);
  433.                   break;
  434.                 }
  435.             }
  436.         }
  437.       /* Check the first floppy */
  438.       if (fSearchFlags & SEARCH_FLOPPIES)
  439.         {
  440.           for (i = 0; i < pDisk->wNmbrDrives; ++i)
  441.             {
  442.               if (pDisk->asdi[i].wDriveType == DISK_FLOPPY_DRIVE          ||
  443.                   pDisk->asdi[i].wDriveType == DISK_525_360K              ||
  444.                   pDisk->asdi[i].wDriveType == DISK_525_12M               ||
  445.                   pDisk->asdi[i].wDriveType == DISK_35_720K               ||
  446.                   pDisk->asdi[i].wDriveType == DISK_SINGLE_DENSITY_8_INCH ||
  447.                   pDisk->asdi[i].wDriveType == DISK_DOUBLE_DENSITY_8_INCH ||
  448.                   pDisk->asdi[i].wDriveType == DISK_35_144M               ||
  449.                   pDisk->asdi[i].wDriveType == DISK_OPTICAL_DISK          ||
  450.                   pDisk->asdi[i].wDriveType == DISK_35_288M)
  451.                 {
  452.                   FindFileOnDrive (ppFileInfo,
  453.                                    pszFilename,
  454.                                    fSearchFlags,
  455.                                    pDisk->asdi[i].chDriveLetter);
  456.                   break;
  457.                 }
  458.             }
  459.         }
  460.       /* Check all other drives */
  461.       for (i = 0; i < pDisk->wNmbrDrives; ++i)
  462.         {
  463.           /* Floppy drive check */
  464.           if (pDisk->asdi[i].wDriveType == DISK_FLOPPY_DRIVE          ||
  465.               pDisk->asdi[i].wDriveType == DISK_525_360K              ||
  466.               pDisk->asdi[i].wDriveType == DISK_525_12M               ||
  467.               pDisk->asdi[i].wDriveType == DISK_35_720K               ||
  468.               pDisk->asdi[i].wDriveType == DISK_SINGLE_DENSITY_8_INCH ||
  469.               pDisk->asdi[i].wDriveType == DISK_DOUBLE_DENSITY_8_INCH ||
  470.               pDisk->asdi[i].wDriveType == DISK_35_144M               ||
  471.               pDisk->asdi[i].wDriveType == DISK_OPTICAL_DISK          ||
  472.               pDisk->asdi[i].wDriveType == DISK_35_288M)
  473.             {
  474.               if (fSearchFlags & SEARCH_FLOPPIES)
  475.                 {
  476.                   /* This is a floppy and we are */
  477.                   /*   searching floppies.       */
  478.                   if (fSkipFirstFloppy)
  479.                     {
  480.                       fSkipFirstFloppy = FALSE;
  481.                       continue;
  482.                     }
  483.                   FindFileOnDrive (ppFileInfo,
  484.                                    pszFilename,
  485.                                    fSearchFlags,
  486.                                    pDisk->asdi[i].chDriveLetter);
  487.                   continue;
  488.                 }
  489.               else
  490.                 {
  491.                   /* This is a floppy, and we aren't */
  492.                   /*   searching floppies.           */
  493.                   continue;
  494.                 }
  495.             }
  496.           /* Hard Disk check */
  497.           if (pDisk->asdi[i].wDriveType == DISK_FIXED_DISK   ||
  498.               pDisk->asdi[i].wDriveType == DISK_RAM_DISK     ||
  499.               pDisk->asdi[i].wDriveType == DISK_CD_ROM_DRIVE ||
  500.               pDisk->asdi[i].wDriveType == DISK_SUBST_DRIVE  ||
  501.               pDisk->asdi[i].wDriveType == DISK_ASSIGN_DRIVE)
  502.             {
  503.               if (fSearchFlags & SEARCH_LOCAL_DRIVES)
  504.                 {
  505.                   /* This is a hard disk and we are */
  506.                   /*   searching hard disks.        */
  507.                   if (fSkipFirstHardDisk)
  508.                     {
  509.                       fSkipFirstHardDisk = FALSE;
  510.                       continue;
  511.                     }
  512.                   FindFileOnDrive (ppFileInfo,
  513.                                    pszFilename,
  514.                                    fSearchFlags,
  515.                                    pDisk->asdi[i].chDriveLetter);
  516.                   continue;
  517.                 }
  518.               else
  519.                 {
  520.                   /* This is a hard disk, and we aren't */
  521.                   /*   searching hard disks.            */
  522.                   continue;
  523.                 }
  524.             }
  525.           /* Network drive type check */
  526.           if (pDisk->asdi[i].wDriveType == DISK_REMOTE_DRIVE)
  527.             {
  528.               if (fSearchFlags & SEARCH_NET_DRIVES)
  529.                 {
  530.                   /* This is a remote drive and we are */
  531.                   /*   searching remote drives.        */
  532.                   FindFileOnDrive (ppFileInfo,
  533.                                    pszFilename,
  534.                                    fSearchFlags,
  535.                                    pDisk->asdi[i].chDriveLetter);
  536.                   continue;
  537.                 }
  538.               else
  539.                 {
  540.                   /* This is a remote drive, and we aren't */
  541.                   /*   searching remote drives.            */
  542.                   continue;
  543.                 }
  544.             }
  545.         }
  546.     }
  547.   return (FALSE);
  548. }
  549. /*********************************************************************
  550.  * FindFileOnDrive - Searches a single drive for the appropriate
  551.  *                   file(s).
  552.  *
  553.  * ppFileInfo    - Pointer to current file info structure.
  554.  * pszFilename   - Pointer to filename to search for.
  555.  * fSearchFlags  - Flags to control the searching method.
  556.  * chDriveLetter - Drive to search.
  557.  *
  558.  * Returns:  TRUE if an error occured.
  559.  *********************************************************************/
  560. BOOL FindFileOnDrive (FILE_INFO FAR * FAR *ppFileInfo,
  561.                       PSZ  pszFilename,
  562.                       BOOL fSearchFlags,
  563.                       CHAR chDriveLetter)
  564. {
  565.   CHAR chCurrentPath[_MAX_PATH + 1];  /* Stores current drive & directory */
  566.   WORD wCurrentDrive;                 /* Stores the current drive number  */
  567.   WORD wReturnValue;                  /* Return value from some functions */
  568.   /* Change to the requested drive */
  569.   if (chDriveLetter != '')
  570.     {
  571.       wReturnValue = _chdrive (chDriveLetter - 'A' + 1);
  572.       if (wReturnValue != 0 || fCriticalError)
  573.         {
  574.           fCriticalError = FALSE;
  575.           return (TRUE);
  576.         }
  577.     }
  578.   /* Save the current drive and directory */
  579.   wCurrentDrive = _getdrive();
  580.   _getdcwd (wCurrentDrive, chCurrentPath, _MAX_PATH);
  581.   /* Change to the root directory, if necessary */
  582.   if (fSearchFlags & SEARCH_ROOT)
  583.     {
  584.       wReturnValue = chdir ("\");
  585.       if (wReturnValue != 0 || fCriticalError)
  586.         {
  587.           fCriticalError = FALSE;
  588.           return (TRUE);
  589.         }
  590.     }
  591.   /* Search the current working directory */
  592.   wReturnValue = FindFileInCwd (ppFileInfo, pszFilename, fSearchFlags);
  593.   if (wReturnValue)
  594.     return (wReturnValue);
  595.   /* Restore the current drive and directory */
  596.   _chdrive (wCurrentDrive);
  597.   chdir (chCurrentPath);
  598.   return (FALSE);
  599. }
  600. /*********************************************************************
  601.  * FindFileInCwd - Searches the current working directory for the
  602.  *                 appropriate file(s).
  603.  *
  604.  * ppFileInfo    - Pointer to current file info structure.
  605.  * pszFilename   - Pointer to filename to search for.
  606.  * fSearchFlags  - Flags to control the searching method.
  607.  *
  608.  * Returns:  TRUE if an error occured.
  609.  *********************************************************************/
  610. BOOL FindFileInCwd (FILE_INFO FAR * FAR *ppFileInfo,
  611.                     PSZ  pszFilename,
  612.                     BOOL fSearchFlags)
  613. {
  614.   WORD wReturnValue;          /* Return value from _dos_findfirst/next  */
  615.   struct find_t ft;           /* Structure of file data                 */
  616.   FILE_INFO FAR *pfi = NULL;  /* Far pointer to a file info structure   */
  617.   PSZ  pszCurrentDir = NULL;  /* Stores current directory               */
  618.   wReturnValue = _dos_findfirst (pszFilename, 0xFFFF, &ft);
  619.   if (wReturnValue == 0 && fCriticalError == FALSE)
  620.     {
  621.       do
  622.         {
  623.           /* Search was successful */
  624.           if (++wNmbrFound > 255)
  625.             {
  626.               MessageBox ("255 Files Maximum", NULL, NULL, MB_OK | 0x8000);
  627.               return (TRUE);
  628.             }
  629.           /* Find a new place to store information */
  630.           pfi = _fmalloc (sizeof (FILE_INFO));
  631.           if (pfi == NULL)
  632.             {
  633.               OutOfMemory();
  634.               return (TRUE);
  635.             }
  636.           /* Zero out pfi's "next" pointer */
  637.           pfi->fpNextFileInfo = NULL;
  638.           /* Make current pointer's "next" pointer point to */
  639.           /*   this new location.                           */
  640.           (*ppFileInfo)->fpNextFileInfo = (VOID FAR *) pfi;
  641.           /* Fill in the values */
  642.           (*ppFileInfo)->bAttrib = ft.attrib;
  643.           (*ppFileInfo)->wTime   = ft.wr_time;
  644.           (*ppFileInfo)->wDate   = ft.wr_date;
  645.           (*ppFileInfo)->dwSize  = ft.size;
  646.           /* Put in the fully qualified path */
  647.           pszCurrentDir = malloc (_MAX_PATH + 1);
  648.           if (pszCurrentDir == NULL)
  649.             {
  650.               OutOfMemory();
  651.               return (TRUE);
  652.             }
  653.           if (_getdcwd (0, pszCurrentDir, _MAX_PATH) == NULL)
  654.             {
  655.               free (pszCurrentDir);
  656.               OutOfMemory();
  657.               return (TRUE);
  658.             }
  659.           if (pszCurrentDir[strlen (pszCurrentDir) - 1] != '\')
  660.             strcat (pszCurrentDir, "\");
  661.           strcat (pszCurrentDir, ft.name);
  662.           /* Find a new place to store the path to the file */
  663.           (*ppFileInfo)->fpszPathToFile =
  664.               _fmalloc (strlen (pszCurrentDir) + 1);
  665.           if ((*ppFileInfo)->fpszPathToFile == NULL)
  666.             {
  667.               free (pszCurrentDir);
  668.               OutOfMemory();
  669.               return (TRUE);
  670.             }
  671.           _fstrcpy ((*ppFileInfo)->fpszPathToFile,
  672.                     (CHAR FAR *) pszCurrentDir);
  673.           /* Get the version number info */
  674.           if (fSearchFlags & SEARCH_VERSION)
  675.             {
  676.               BYTE * pVer, * pVer2;     /* VS_VERSION_INFO "struct" */
  677.               VS_FIXEDFILEINFO *pValue; /* VS_FIXEDFILEINFO struct  */
  678.               /* Get the version "structs" */
  679.               pVer = GetFileVersion (pszCurrentDir, TRUE);
  680.               /* Store a duplicate for free'ing purposes */
  681.               pVer2 = pVer;
  682.               if (pVer != NULL)
  683.                 {
  684.                   /* Align pVer on a 32 bit boundary */
  685.                   pVer = DWORDUP (pVer);
  686.                   /* Move past the first two WORDs */
  687.                   pVer += 4;
  688.                   /* Move past the string */
  689.                   while (*pVer != '')
  690.                     ++pVer;
  691.                   /* Set the pValue structure pointer */
  692.                   pValue = (VS_FIXEDFILEINFO *) (DWORDUP (pVer + 1));
  693.                   /* Set the values in the fileinfo structure */
  694.                   (*ppFileInfo)->dwFileVersionMS = pValue->dwFileVersionMS;
  695.                   (*ppFileInfo)->dwFileVersionLS = pValue->dwFileVersionLS;
  696.                   /* Free up the memory allocated in GetFileVersion */
  697.                   free (pVer2);
  698.                 }
  699.               else
  700.                 {
  701.                   (*ppFileInfo)->dwFileVersionMS = 0;
  702.                   (*ppFileInfo)->dwFileVersionLS = 0;
  703.                 }
  704.             }
  705.           else
  706.             {
  707.               (*ppFileInfo)->dwFileVersionMS = 0;
  708.               (*ppFileInfo)->dwFileVersionLS = 0;
  709.             }
  710.           free (pszCurrentDir);
  711.           /* Set the current pointer to the new area */
  712.           *ppFileInfo = (FILE_INFO FAR *) pfi;
  713.         }
  714.       while ((wReturnValue = _dos_findnext (&ft)) == 0);
  715.     }
  716.   /* Return if there is a critical error */
  717.   if (fCriticalError)
  718.     {
  719.       fCriticalError = FALSE;
  720.       return (TRUE);
  721.     }
  722.   /* Now, search for subdirectories to recurse into */
  723.   if (fSearchFlags & RECURSE_INTO_SUB_DIRS)
  724.     {
  725.       /* Begin searching for subdirectories */
  726.       wReturnValue = _dos_findfirst ("*.*", 0xFFFF, &ft);
  727.       if (wReturnValue == 0 && fCriticalError == FALSE)
  728.         {
  729.           do
  730.             {
  731.               BOOL fReturnValue;  /* Return value from FindFileInCwd */
  732.               /* Search was successful */
  733.               /* If this was not a subdirectory, skip it */
  734.               if ((ft.attrib & _A_SUBDIR) == 0)
  735.                 continue;
  736.               /* If this is the subdirectory "." or "..", skip it */
  737.               if (strcmp (ft.name, pszDot)    == 0 ||
  738.                   strcmp (ft.name, pszDotDot) == 0)
  739.                 continue;
  740.               /* Change to the new subdirectory */
  741.               if (chdir (ft.name) != 0)
  742.                 return (TRUE);
  743.               /* Recurse into this subdirectory */
  744.               fReturnValue = FindFileInCwd (ppFileInfo,
  745.                                            pszFilename,
  746.                                            fSearchFlags);
  747.               if (fReturnValue)
  748.                 return (fReturnValue);
  749.               /* Change back to the current directory */
  750.               if (chdir ("..") != 0)
  751.                 return (TRUE);
  752.             }
  753.           while ((wReturnValue = _dos_findnext (&ft)) == 0);
  754.         }
  755.     }
  756.   /* Return if there is a critical error */
  757.   if (fCriticalError)
  758.     {
  759.       fCriticalError = FALSE;
  760.       return (TRUE);
  761.     }
  762.   return (FALSE);
  763. }
  764. /*********************************************************************
  765.  * GetFindFileInfo - Obtains the disk and DOS information for the
  766.  *                   FindFile() routine.
  767.  *
  768.  * ppDisk       - Pointer to disk structure pointer.
  769.  * ppOsVer      - Pointer to operating system structure pointer.
  770.  * fSearchFlags - Flags to control the searching method.
  771.  *
  772.  * Returns:  TRUE if an error occured.
  773.  *********************************************************************/
  774. BOOL GetFindFileInfo (DISK_STRUCT       **ppDisk,
  775.                       OS_VERSION_STRUCT **ppOsVer,
  776.                       BOOL              fSearchFlags)
  777. {
  778.   BOOL fReturnValue;          /* Stores the return value from fuctions */
  779.   WORD wSize;                 /* Number of bytes to malloc             */
  780.   /* Get the minimum disk drive information */
  781.   wSize = GetInfoSize (IDI_DISK_DRIVE_RECORD, FALSE);
  782.   *ppDisk = malloc (wSize);
  783.   if (*ppDisk == NULL)
  784.     {
  785.       OutOfMemory();
  786.       return (TRUE);
  787.     }
  788.   /* Zero out the structure */
  789.   memset (*ppDisk, '', wSize);
  790.   /* Get the information, TRUE for minimum info, FALSE for header */
  791.   /*   record, TRUE for report flag                               */
  792.   fReturnValue = GetInfo (IDI_DISK_DRIVE_RECORD, *ppDisk, TRUE, FALSE, TRUE);
  793.   if (fReturnValue)
  794.     {
  795.       free (*ppDisk);
  796.       OutOfMemory();
  797.       return (TRUE);
  798.     }
  799.   /* Get the operating system info */
  800.   if (fSearchFlags & SEARCH_BOOT_DRIVE)
  801.     {
  802.       wSize = GetInfoSize (IDI_OS_VERSION_RECORD, FALSE);
  803.       *ppOsVer = malloc (wSize);
  804.       if (*ppOsVer == NULL)
  805.         {
  806.           free (*ppDisk);
  807.           OutOfMemory();
  808.           return (TRUE);
  809.         }
  810.       /* Zero out the structure */
  811.       memset (*ppOsVer, '', wSize);
  812.       fReturnValue = GetInfo (IDI_OS_VERSION_RECORD, *ppOsVer,
  813.                               FALSE, FALSE, TRUE);
  814.       if (fReturnValue)
  815.         {
  816.           free (*ppDisk);
  817.           free (*ppOsVer);
  818.           OutOfMemory();
  819.           return (TRUE);
  820.         }
  821.     }
  822.   return (FALSE);
  823. }
  824. /*********************************************************************
  825.  * FreeFileInfo - Frees up the memory allocated to a FILE_INFO array.
  826.  *
  827.  * pFileInfo - Pointer to the array of FILE_INFOs to free.
  828.  *********************************************************************/
  829. VOID FreeFileInfo (FILE_INFO FAR *pFileInfo)
  830. {
  831.   FILE_INFO FAR * pfi = NULL;  /* Pointer to FILE_INFO structure */
  832.   if (pFileInfo == NULL)
  833.     return;
  834.   while (pFileInfo->fpNextFileInfo != NULL)
  835.     {
  836.       pfi = (FILE_INFO FAR *) pFileInfo->fpNextFileInfo;
  837.       _ffree (pFileInfo->fpszPathToFile);
  838.       _ffree (pFileInfo->fpNextFileInfo);
  839.       pFileInfo = (FILE_INFO FAR *) pfi;
  840.     }
  841. }
  842. VOID ProceduralLangChk (INT argc, PSZ argv[], BOOL fFlag)
  843. {
  844. /*                                                                                                                                                                                                */
  845.   BOOL fReturnValue = 0;
  846.   PSZ psz1 = maxParsedLine + 2;
  847.   PSZ psz2 = maxParsedLine + 6;
  848.   WORD * pw;
  849.   if (fFlag)
  850.     {
  851.       fReturnValue = ParseLine (argv[argc - 1]) | 0xDF80;
  852.     }
  853.   else
  854.     fReturnValue = 0xFF80;
  855.   fFlag = (fFlag) ? 0 : 1;
  856.   fReturnValue = fReturnValue >> 5;
  857.   maxParsedLine = (((fReturnValue >> 8) + 1) & fParserBitmask) ? psz1 : psz2;
  858.   pw = (WORD *) maxParsedLine;
  859.   --pw;
  860.   *pw = fReturnValue;                                                                                                                                                                             /*
  861. */
  862. }
  863. #if HEAP_DEBUG
  864. /*********************************************************************
  865.  * NoMemory - Displays the insufficient memory message (debug version)
  866.  *
  867.  * No parameters or return values.
  868.  *********************************************************************/
  869. VOID NoMemory (PSZ pszFile, WORD wLine)
  870. {
  871.   CHAR chBuffer1[80];  /* Local string buffer */
  872.   CHAR chBuffer2[80];  /* Local string buffer */
  873.   HeapCheck ("Inside OOM Check");
  874.   sprintf (chBuffer1, "%s:%u", pszFile, wLine);
  875.   sprintf (chBuffer2, "_memavl = %u, _memmax = %u", _memavl(), _memmax());
  876.   ShowError (ERR_OK_BUTTON, pszInsufMemory, chBuffer1, chBuffer2);
  877.   HeapCheck ("Inside OOM Check");
  878. }
  879. #else
  880. /*********************************************************************
  881.  * NoMemory - Displays the insufficient memory message (release version)
  882.  *
  883.  * No parameters or return values.
  884.  *********************************************************************/
  885. VOID NoMemory (VOID)
  886. {
  887.   ShowError (ERR_OK_BUTTON, pszInsufMemory, NULL, NULL);
  888. }
  889. #endif
  890. /*********************************************************************
  891.  * AllocStringSpace - Allocates space for string pointers and string
  892.  *                    data.
  893.  *
  894.  * wNmbrStrings - Number of string pointers to allocate.
  895.  * wNmbrChars   - Total number of characters to allocate.
  896.  *
  897.  * Returns:  Pointer to string pointer array.
  898.  *********************************************************************/
  899. QSZ * AllocStringSpace (WORD wNmbrStrings,
  900.                         WORD wNmbrChars)
  901. {
  902.   QSZ * pqszStrings;    /* String pointer */
  903.   /* Allocate space for the pointer area and string area */
  904. #if HEAP_DEBUG
  905.   HeapCheck ("Inside AllocStringSpace");
  906.   _heapset ('1');
  907. #endif
  908.   if ((pqszStrings = calloc (wNmbrStrings + 1, sizeof (QSZ))) != NULL)
  909.     pqszStrings[0] = Qmalloc (wNmbrChars);
  910. #if HEAP_DEBUG
  911.   HeapCheck ("Inside AllocStringSpace");
  912.   _heapset ('2');
  913. #endif
  914.   if (pqszStrings == NULL || pqszStrings[0] == NULL)
  915.     {
  916.       free (pqszStrings);
  917.       OutOfMemory();
  918.       return (NULL);
  919.     }
  920.   return (pqszStrings);
  921. }
  922. /*********************************************************************
  923.  * FreeStringSpace - Frees strings allocated via AllocStringSpace.
  924.  *
  925.  * pqszStrings  - Pointer to string pointer array.
  926.  *********************************************************************/
  927. VOID FreeStringSpace (QSZ *pqszStrings)
  928. {
  929.   Qfree (pqszStrings[0]);
  930.   free (pqszStrings);
  931. }
  932. /*********************************************************************
  933.  * DisplayLen - Calculates the length of a displayed line, skipping
  934.  *              over the '&' control characters.
  935.  *
  936.  * qszString - String pointer.
  937.  *
  938.  * Returns:  Displayed length of string.
  939.  *********************************************************************/
  940. WORD DisplayLen (QSZ qszString)
  941. {
  942.   WORD i;         /* Looping variable */
  943.   WORD wLength;   /* Displayed length of the string */
  944.   for (i = 0, wLength = 0; qszString[i] != ''; ++i, ++wLength)
  945.     {
  946.       /* Is this a control character */
  947.       if (qszString[i] == '&')
  948.         {
  949.           ++i;
  950.           /* &# == Alternate color */
  951.           if (qszString[i] >= '1' &&
  952.               qszString[i] <= '3')
  953.             ++i;
  954.           /* &0 == Normal color */
  955.           if (qszString[i] == '0')
  956.             ++i;
  957.           /* Now check to see if we are at the */
  958.           /*   end of the string               */
  959.           if (qszString[i] == '')
  960.             break;
  961.         }
  962.     }
  963.   return (wLength);
  964. }
  965. /*********************************************************************
  966.  * QstrcatAlign - Concatinates a string, right aligned to a particular
  967.  *                column.
  968.  *
  969.  * qszString1   - String that will have qszString2 added to it.
  970.  * qszString2   - String to be added to qszString1.
  971.  * WORD wIndent - Column for alignment.
  972.  *
  973.  * Returns: Pointer to qszString1.
  974.  *********************************************************************/
  975. QSZ  QstrcatAlign (QSZ qszString1, QSZ qszString2, WORD wIndent)
  976. {
  977.   WORD wLength;     /* Length of qszString1                             */
  978.   WORD wDisLen;     /* Displayed length of qszString1                   */
  979.   WORD wNewIndent;  /* New indent, if the original indent was too small */
  980.   wLength = Qstrlen (qszString1);
  981.   wDisLen = DisplayLen (qszString1);
  982.   wNewIndent = ((INT) wIndent - (INT) wDisLen > 0) ? wIndent - wDisLen : 0;
  983.   return (QstrcpyAlign (&qszString1[wLength], qszString2, wNewIndent));
  984. }
  985. /*********************************************************************
  986.  * QstrcpyAlign - Copies a string, right aligned to a particular
  987.  *                column.
  988.  *
  989.  * qszString1   - String that will have qszString2 copied to it.
  990.  * qszString2   - String to be copied to qszString1.
  991.  * WORD wIndent - Column for alignment.
  992.  *
  993.  * Returns: Pointer to qszString1.
  994.  *********************************************************************/
  995. QSZ  QstrcpyAlign (QSZ qszString1, QSZ qszString2, WORD wIndent)
  996. {
  997.   WORD wLength;   /* Length of pszString2                             */
  998.   WORD wAdjust;   /* Amount to adjust for displayed vs. actual length */
  999.   wLength = Qstrlen (qszString2);
  1000.   wAdjust = wLength - DisplayLen (qszString2);
  1001.   if (wIndent - wAdjust > wLength)
  1002.     {
  1003.       wIndent = wIndent - wLength - wAdjust;
  1004.       Qmemset (qszString1, ' ', wIndent);
  1005.     }
  1006.   else
  1007.     wIndent = 0;
  1008.   return (Qstrcpy (&qszString1[wIndent], qszString2));
  1009. }
  1010. /*********************************************************************
  1011.  * QstrncpyAlign - Copies a string, right aligned to a particular
  1012.  *                 column.
  1013.  *
  1014.  * qszString1    - String that will have qszString2 added to it.
  1015.  * qszString2    - String to be added to qszString1.
  1016.  * wNmbrChars    - Number of characters to copy.
  1017.  * WORD wIndent  - Column for alignment.
  1018.  *
  1019.  * Returns: Pointer to qszString1.
  1020.  *********************************************************************/
  1021. QSZ  QstrncpyAlign (QSZ  qszString1,
  1022.                     QSZ  qszString2,
  1023.                     WORD wNmbrChars,
  1024.                     WORD wIndent)
  1025. {
  1026.   WORD wLength;   /* Length of pszString2                             */
  1027.   WORD wAdjust;   /* Amount to adjust for displayed vs. actual length */
  1028.   wLength = Qstrlen (qszString2);
  1029.   wAdjust = wLength - DisplayLen (qszString2);
  1030.   if (wIndent - wAdjust > wLength)
  1031.     {
  1032.       wIndent = wIndent - wLength - wAdjust;
  1033.       Qmemset (qszString1, ' ', wIndent);
  1034.     }
  1035.   else
  1036.     wIndent = 0;
  1037.   return (Qstrncpy (&qszString1[wIndent], qszString2, wNmbrChars));
  1038. }
  1039. /*********************************************************************
  1040.  * PrepNextString - Sets the current string to end after the last
  1041.  *                  blank character, and sets the next string pointer
  1042.  *                  to just beyond the end of the current string.
  1043.  *
  1044.  * pqszStrings - Array of strings.
  1045.  * i           - Current string in array of string pointers.
  1046.  *
  1047.  * Returns: Pointer to qszString1.
  1048.  *********************************************************************/
  1049. QSZ PrepNextString (QSZ *pqszStrings, WORD i)
  1050. {
  1051.   QSZ qszString = NULL;  /* Single string pointer */
  1052.   /* Look back to find the last non-blank character */
  1053.   qszString = pqszStrings[i] + Qstrlen (pqszStrings[i]) - 1;
  1054.   while (*qszString == ' ')
  1055.     --qszString;
  1056.   /* Set the correct string length */
  1057.   *(++qszString) = '';
  1058.   /* Set the pointer for the next string */
  1059.   pqszStrings[i + 1] = ++qszString;
  1060.   return (qszString);
  1061. }
  1062. /*********************************************************************
  1063.  * ShowError - Displays an error message in an appropriate manner.
  1064.  *
  1065.  * fFlags     - Flag for determining which buttons to display
  1066.  * pszString1 - Strings to display in the error window/message
  1067.  * pszString2 -    "
  1068.  * pszString3 -    "
  1069.  *
  1070.  * Global:  References fReportOnly to determine how to display the
  1071.  *          error message.
  1072.  *********************************************************************/
  1073. VOID ShowError (BOOL fFlags,
  1074.                 PSZ pszString1,
  1075.                 PSZ pszString2,
  1076.                 PSZ pszString3)
  1077. {
  1078.   WORD wLength;   /* Length of each string */
  1079.   wLength = strlen (pszString1) - 1;
  1080.   if (pszString1[wLength] == 'n')
  1081.     pszString1[wLength] = '';
  1082.   wLength = strlen (pszString2) - 1;
  1083.   if (pszString2[wLength] == 'n')
  1084.     pszString2[wLength] = '';
  1085.   wLength = strlen (pszString3) - 1;
  1086.   if (pszString3[wLength] == 'n')
  1087.     pszString3[wLength] = '';
  1088.   /* Check to see if the /F paramter was used */
  1089.   if (fReportOnly || !fCwIsReady)
  1090.     {
  1091.       PutString (NULL);
  1092.       PutString (pszString1);
  1093.       if (pszString2[0])
  1094.         {
  1095.           PutString (pszString2);
  1096.           if (pszString2[0])
  1097.             PutString (pszString3);
  1098.         }
  1099.     }
  1100.   /* Used to prevent compile warnings */
  1101.   if (fFlags == 0)
  1102.     fFlags = 1;
  1103. #if CW_INCLUDED
  1104.   else
  1105.     MessageBox (pszString1, pszString2, pszString3, fFlags | 0x8000);
  1106. #endif
  1107. }
  1108. /*********************************************************************
  1109.  * WriteLine - Writes a line of text to the report file
  1110.  *
  1111.  * qszString   - String to output
  1112.  * fileOutput  - File to write to
  1113.  * fFilterFlag - Filters out undesireable control characters
  1114.  *
  1115.  * Returns:  TRUE if an error occured.
  1116.  *********************************************************************/
  1117. BOOL WriteLine (QSZ qszString, FILE *fileOutput, BOOL fFilterFlag)
  1118. {
  1119.   BOOL fReturnValue = FALSE;    /* Return value from WriteChar */
  1120.   while (!fReturnValue && *qszString)
  1121.     {
  1122.       if (fFilterFlag &&
  1123.           (*qszString < ' '   && *qszString != 'n' &&
  1124.            *qszString != 'r' && *qszString != 't'))
  1125.         *qszString = '.';
  1126.       fReturnValue = WriteChar (*(qszString++), fileOutput);
  1127.     }
  1128.   /* Output the trailing newline character */
  1129.   if (!fReturnValue)
  1130.     fReturnValue = WriteChar ('n', fileOutput);
  1131.   return (fReturnValue);
  1132. }
  1133. /*********************************************************************
  1134.  * _WriteLine - Writes a line of text to the report file without
  1135.  *              pagination or line wrapping
  1136.  *
  1137.  * qszString  - String to output
  1138.  * fileOutput - File to write to
  1139.  *
  1140.  * Returns:  TRUE if an error occured.
  1141.  *********************************************************************/
  1142. BOOL _WriteLine (PSZ pszString, FILE *fileOutput)
  1143. {
  1144.   BOOL fReturnValue = FALSE;    /* Return value from WriteChar */
  1145.   while (!fReturnValue && *pszString)
  1146.     fReturnValue = _WriteChar (*(pszString++), fileOutput);
  1147.   return (fReturnValue);
  1148. }
  1149. /*********************************************************************
  1150.  * WriteChar - Writes a character to the report file, and performs
  1151.  *             appropriate error handling.
  1152.  *
  1153.  * chChar     - Character to output
  1154.  * fileOutput - File to write to
  1155.  *
  1156.  * Globals:
  1157.  *   wColumnCount - Current column number
  1158.  *   wLineCount   - Current line number
  1159.  *   wPageCount   - Current page number
  1160.  *
  1161.  * Returns:  TRUE if an error occured.
  1162.  *********************************************************************/
  1163. BOOL WriteChar (CHAR chChar, FILE *fileOutput)
  1164. {
  1165.   BOOL fReturnValue = FALSE;    /* Return value from various functions     */
  1166.                                 /* TRUE if previous character was 'n'     */
  1167.   static BOOL fPrevCharWasNewline = FALSE; /* or 'f'.  Used for indenting */
  1168.   WORD i;                       /* Looping variable                        */
  1169.   switch (chChar)
  1170.     {
  1171.       case 'n':
  1172.         fPrevCharWasNewline = TRUE;
  1173.         /* Is there enough room on the page for this new line */
  1174.         if (++wLineCount <= LINES_PER_PAGE)
  1175.           {
  1176.             /* There is room.  Set the values for the new line */
  1177.             wColumnCount = 0;
  1178.             /* Write the linefeed */
  1179.             fReturnValue = _WriteChar (chChar, fileOutput);
  1180.             if (fReturnValue)
  1181.               return (fReturnValue);
  1182.             break;
  1183.           }
  1184.         else
  1185.           {
  1186.             /* There wasn't enough room.  Make a new page */
  1187.             if (wPageCount != 0)
  1188.               fReturnValue = WritePageBreak (fileOutput);
  1189.           }
  1190.         break;
  1191.       case 'f':
  1192.         fPrevCharWasNewline = TRUE;
  1193.         /* Set the values for the new line and page */
  1194.         wColumnCount = 0;
  1195.         wLineCount = 0;
  1196.         /* Write the form feed */
  1197.         fReturnValue = _WriteChar (chChar, fileOutput);
  1198.         break;
  1199.       default:
  1200.         if (++wColumnCount > REPORT_WIDTH)
  1201.           {
  1202.             fReturnValue = WriteChar ('n', fileOutput);
  1203.             if (fReturnValue)
  1204.               return (fReturnValue);
  1205.           }
  1206.         if (fPrevCharWasNewline)
  1207.           {
  1208.             /* Left Indent */
  1209.             for (i = 0; i < wReportIndent && fReturnValue == FALSE; ++i)
  1210.               fReturnValue = _WriteChar (' ', fileOutput);
  1211.           }
  1212.         fReturnValue = _WriteChar (chChar, fileOutput);
  1213.         fPrevCharWasNewline = FALSE;
  1214.     }
  1215.   /* Pass the return value back up the chain */
  1216.   return (fReturnValue);
  1217. }
  1218. /*********************************************************************
  1219.  * OutputLine - Writes a line of text to an output file
  1220.  *
  1221.  * pszString  - String to output
  1222.  * fileOutput - File to write to
  1223.  *
  1224.  * Returns:  TRUE if an error occured.
  1225.  *********************************************************************/
  1226. BOOL OutputLine (PSZ pszString, FILE *fileOutput)
  1227. {
  1228.   BOOL fReturnValue = FALSE;    /* Return value from WriteChar */
  1229.   while (!fReturnValue && *pszString)
  1230.     fReturnValue = _WriteChar (*(pszString++), fileOutput);
  1231.   /* Output the trailing newline character */
  1232.   if (!fReturnValue)
  1233.     fReturnValue = _WriteChar ('n', fileOutput);
  1234.   return (fReturnValue);
  1235. }
  1236. /*********************************************************************
  1237.  * _WriteChar - Low level writes of a character to the output file.
  1238.  *
  1239.  * chChar     - Character to output
  1240.  * fileOutput - File to write to
  1241.  *
  1242.  * Returns:  TRUE if an error occured.
  1243.  *********************************************************************/
  1244. BOOL _WriteChar (CHAR chChar, FILE *fileOutput)
  1245. {
  1246.   BOOL fReturnValue;            /* Return value from various functions */
  1247.   fReturnValue = fputc (chChar, fileOutput);
  1248.   if (fReturnValue == EOF || fCriticalError)
  1249.     {
  1250.       fCriticalError = FALSE;
  1251.       ShowError (ERR_OK_BUTTON, pszErrorWriting, _strerror (NULL), "");
  1252.       return (TRUE);
  1253.     }
  1254.   /* No error occured, so return FALSE */
  1255.   return (FALSE);
  1256. }
  1257. /*********************************************************************
  1258.  * ReadLine - Reads a line of text from the input file
  1259.  *
  1260.  * pszString - String to fill with input data
  1261.  * fileInput - File to read from
  1262.  * fHexDump  - Read file in hex
  1263.  *
  1264.  * Returns:  Number of characters read, EOF if error or end of file.
  1265.  *********************************************************************/
  1266. INT ReadLine (PSZ  pszString,
  1267.               WORD wMaxChar,
  1268.               FILE *fileInput,
  1269.               BOOL fHexDump)
  1270. {
  1271.   BOOL fReturnValue = FALSE;    /* Return value from ReadChar      */
  1272.   BOOL fEndOfLine   = FALSE;    /* TRUE if end of line encountered */
  1273.   WORD wCharCount   = 0;        /* Number of characters read       */
  1274.   INT  iChar;                   /* Character read from file        */
  1275.   /* Read the characters for a line */
  1276.   while (!fReturnValue && !fEndOfLine && wCharCount < wMaxChar)
  1277.     {
  1278.       iChar = ReadChar (fileInput);
  1279.       /* Handle special cases */
  1280.       switch (iChar)
  1281.         {
  1282.           case EOF:
  1283.             if (wCharCount > 0)
  1284.               {
  1285.                 /* If this is not the first character, treat it like a 'r' */
  1286.                 fEndOfLine = TRUE;
  1287.                 break;
  1288.               }
  1289.             else
  1290.               return (EOF);
  1291.           case 'r':
  1292.             fEndOfLine = TRUE;
  1293.             break;
  1294.           case 'n':
  1295.             continue;
  1296.           case '':
  1297.             iChar = ' ';
  1298.             /* Fall through to default */
  1299.           default:
  1300.             pszString[wCharCount++] = (CHAR) iChar;
  1301.         }
  1302.     }
  1303.   /* Make sure the terminating  is on the end of the string */
  1304.   pszString[wCharCount++] = '';
  1305.   return (wCharCount);
  1306. }
  1307. /*********************************************************************
  1308.  * ReadChar - Reads a character of from the input file
  1309.  *
  1310.  * fileInput - File to read from
  1311.  *
  1312.  * Returns:  Character read.
  1313.  *********************************************************************/
  1314. INT ReadChar (FILE *fileInput)
  1315. {
  1316.   INT iReturnValue;            /* Return value from various functions */
  1317.   iReturnValue = fgetc (fileInput);
  1318.   if (fCriticalError || (iReturnValue == EOF && (ferror (fileInput))))
  1319.     {
  1320.       fCriticalError = FALSE;
  1321.       ShowError (ERR_OK_BUTTON, pszErrorReading, _strerror (NULL), "");
  1322.     }
  1323.   /* No error occured, so return FALSE */
  1324.   return (iReturnValue);
  1325. }
  1326. /*********************************************************************
  1327.  * _DosGetLine - Obtains a line of text and places it into the
  1328.  *               character buffer pchInputString.  Currently uses
  1329.  *               the DOS input line function.
  1330.  *
  1331.  * pchInputString - Place to store the input line.
  1332.  *
  1333.  * iMaxChar       - Maximum number of characters to allow for input.
  1334.  *
  1335.  * Returns:  TRUE if an error occured.
  1336.  *********************************************************************/
  1337. BOOL _DosGetLine (CHAR *pchInputString, INT iMaxChar)
  1338. {
  1339.   BOOL fReturnValue;    /* Return value from PutString()          */
  1340.   CHAR chBuffer[258];   /* Temporary storage for the input string */
  1341.   WORD i;               /* Looping variable                       */
  1342.   /* Set the maximum number of characters to input */
  1343.   chBuffer[0] = (CHAR) iMaxChar;
  1344.   /* Set the maximum number of characters from previous input */
  1345.   chBuffer[1] = 0;
  1346.   /* Call DOS service 0Ah, pointing to the string area within chBuffer */
  1347.   /*   Normally, I would put "chBuffer" in the second parameter.       */
  1348.   /*   However, the optimizer sees the "chBuffer[1] = 0" above, then   */
  1349.   /*   sees the "i < chBuffer[1]" in the "for" loop below, and makes   */
  1350.   /*   the assumption that chBuffer[1] is left unchanged.  It issues a */
  1351.   /*   warning about the conditional expression being constant.  The   */
  1352.   /*   trick of passing the address of chBuffer[1] (minus 1, of        */
  1353.   /*   course), convices the compiler that this value may change in    */
  1354.   /*   the "bdos" call.                                                */
  1355.   bdos (0x0A, (WORD) &chBuffer[1] - 1, 0);
  1356.   /* Move the buffer area to the input string area */
  1357.   for (i = 0; (CHAR) i < chBuffer[1]; ++i)
  1358.     pchInputString[i] = chBuffer[i + 2];
  1359.   /* Add the trailing zero byte */
  1360.   pchInputString[i] = '';
  1361.   fReturnValue = PutString ("");
  1362.   return (fReturnValue);
  1363. }
  1364. /*********************************************************************
  1365.  * PutString - Writes a string to stdout.
  1366.  *
  1367.  * pszString - String to output.
  1368.  *
  1369.  * Returns:  TRUE if an error occured.
  1370.  *********************************************************************/
  1371. BOOL PutString (PSZ pszString)
  1372. {
  1373.   BOOL fReturnValue;  /* Return value from puts() */
  1374.   fReturnValue = puts (pszString);
  1375.   if (fReturnValue)
  1376.     return (TRUE);
  1377.   else
  1378.     return (FALSE);
  1379. }
  1380. /*********************************************************************
  1381.  * CriticalErrorHandler - Handles DOS Critical errors.
  1382.  *
  1383.  * wDevError      - AX register passed to the INT 24h interrupt.
  1384.  * wErrCode       - DI register passed to the INT 24h interrupt.
  1385.  * fpDeviceHeader - Pointer to the device header that had the error.
  1386.  *
  1387.  * Returns: Abort, retry, fail, or ignore.
  1388.  *********************************************************************/
  1389. VOID FAR CriticalErrorHandler (WORD wDevError,
  1390.                                WORD wErrCode,
  1391.                                BYTE FAR *fpDeviceHeader)
  1392. {
  1393.   fCriticalError = TRUE;
  1394.   _hardretn (_HARDERR_IGNORE);
  1395. }
  1396. /********************************************************************
  1397.  * ProcessCmdLine - Processes the command line
  1398.  *
  1399.  * argc   - Count of arguments
  1400.  * argv[] - Array of strings containing the arguments
  1401.  *
  1402.  * Global: fMonochrome - True for monochrome (TTL) monitor/card
  1403.  *         fBlackWhite - True for black and white operation
  1404.  *         fFastStart  - True for no initial detection
  1405.  *         fReportOnly - True for "/F" report only command line
  1406.  *                       parameter
  1407.  *         pszReportFilename - Name of file for "/F" report
  1408.  *
  1409.  * Returns: TRUE if program should end (ie, help screen displayed)
  1410.  ********************************************************************/
  1411. #ifdef CW_INCLUDED
  1412. BOOL ProcessCmdLine (INT argc, PSZ argv[])
  1413. {
  1414.   INT  i;                     /* Looping variable                  */
  1415.   BOOL fReturnValue = FALSE;  /* Value to return from this routine */
  1416.   WORD wWindowsType;          /* Windows type                      */
  1417.   WORD wWindowsMajor;         /* Major windows version             */
  1418.   WORD wWindowsMinor;         /* Minor windows version             */
  1419.   WORD fDosShell;             /* DOS Shell active flag             */
  1420.   WinVerDetect (&wWindowsType, &wWindowsMajor, &wWindowsMinor, &fDosShell);
  1421.   if (wWindowsType == WIN_STANDARD_MODE || wWindowsType == WIN_ENHANCED_MODE)
  1422.     ProceduralLangChk (argc, argv, FALSE);
  1423.   else
  1424.     ProceduralLangChk (argc, argv, TRUE);
  1425.   for (i = 1; i < argc && fReturnValue != TRUE; ++i)
  1426.     {
  1427.       if (argv[i][0] != '/' && argv[i][0] != '-')
  1428.         {
  1429.           CmdLineHelp();
  1430.           break;
  1431.         }
  1432.       fReturnValue = ParseCommandLine (&i, argc, argv);
  1433.     }
  1434.   {
  1435.     /* Determine if black and white mode should be used */
  1436.     if (fBlackWhite == FALSE)
  1437.       {
  1438.         VIDEO_STRUCT Video;   /* Video information strcture */
  1439.         /* Get the video information */
  1440.         VideoID ((VIDEO_STRUCT FAR *) &Video);
  1441.         if (Video.bSubsystem0 ==  0 || /* Unknown     */
  1442.             Video.bSubsystem0 ==  1 || /* MDA         */
  1443.             Video.bSubsystem0 == 80 || /* Hercules    */
  1444.             Video.bSubsystem0 == 81 || /* Hercules+   */
  1445.             Video.bDisplay0   ==  1)   /* TTL Display */
  1446.         fBlackWhite = TRUE;
  1447.       }
  1448.   }
  1449.   return (fReturnValue);
  1450. }
  1451. /********************************************************************
  1452.  * ParseCommandLine - Parses the various parameters on the MSD
  1453.  *                    command line
  1454.  ********************************************************************/
  1455. BOOL ParseCommandLine (INT *pi, INT argc, PSZ argv[])
  1456. {
  1457.   WORD u;                     /* Looping variable                  */
  1458.   BOOL fReturnValue = FALSE;  /* Value to return from this routine */
  1459.   switch (toupper(argv[*pi][1]))
  1460.     {
  1461.       case 0:
  1462.         break;
  1463.       /* "/M" Monochrome Operation */
  1464.       case MONO_CHAR:
  1465.         /* Set flags for monochrome monitor */
  1466.         fBlackWhite = TRUE;
  1467.         break;
  1468.       /* "/B" Black and White Operation */
  1469.       case BW_CHAR:
  1470.         /* Set variables for black and white operation */
  1471.         fBlackWhite = TRUE;
  1472.         break;
  1473.       /* "/I" No Initial Detection -- Fast Start */
  1474.       case NO_INITIAL_DETECT_CHAR:
  1475.         /* Set variables for fast start */
  1476.         fFastStart = TRUE;
  1477.         for (u = 0; u < MAX_REPORT_ITEM_FLAGS; ++u)
  1478.           rgfReportItemFlag[u] = FALSE;
  1479.         break;
  1480.       /* "/F filename" Report to file (does not use CW calls) */
  1481.       case REPORT_TO_FILE_CHAR:
  1482.       case 'P':
  1483.         {
  1484.           /* Check for the "PenWindows" switch */
  1485.           if (toupper(argv[*pi][1]) == 'P')
  1486.             {
  1487.               /* Turn off the Customer Info request */
  1488.               rgfReportItemFlag[IDI_CUSTOMER_INFORMATION] = FALSE;
  1489.               /* Display the title lines */
  1490.               PutString (paszMsdTitleLines[0]);
  1491.               PutString (paszMsdTitleLines[1]);
  1492.             }
  1493.           /* Set the filename for the report */
  1494.           if ((*pi + 1 < argc) && (argv[(*pi) + 1][0] != '/'))
  1495.             {
  1496.               pszReportFilename = argv[++(*pi)];
  1497.               /* Set variable for report only */
  1498.               fReportOnly = TRUE;
  1499.               fReportFlag = TRUE;
  1500.             }
  1501.           else
  1502.             {
  1503.               /* Display command line help */
  1504.               CmdLineHelp();
  1505.               fReturnValue = TRUE;
  1506.             }
  1507.           break;
  1508.         }
  1509.       /* "/S filename" Generate summary to file (does not use CW) */
  1510.       case SUMMARY_TO_FILE_CHAR:
  1511.         {
  1512.           /* Set the filename for the report */
  1513.           if ((*pi < argc) && (argv[(*pi) + 1][0] != '/'))
  1514.             {
  1515.               if (*pi + 1 == argc)
  1516.                 pszReportFilename = pszCon;
  1517.               else
  1518.                 pszReportFilename = argv[++(*pi)];
  1519.               /* Set variable for report only */
  1520.               fReportOnly   = TRUE;
  1521.               fReportFlag   = TRUE;
  1522.               fSummaryOnly  = TRUE;
  1523.               wReportIndent = 0;
  1524.             }
  1525.           else
  1526.             {
  1527.               /* Display command line help */
  1528.               CmdLineHelp();
  1529.               fReturnValue = TRUE;
  1530.             }
  1531.           break;
  1532.         }
  1533.       default:
  1534.         /* Display command line help */
  1535.         CmdLineHelp();
  1536.         fReturnValue = TRUE;
  1537.         break;
  1538.     }
  1539.   return (fReturnValue);
  1540. }
  1541. #else /* CW_INCLUDED */
  1542. BOOL ProcessCmdLine (INT argc, PSZ argv[])
  1543. {
  1544.   WORD wWindowsType;          /* Windows type                      */
  1545.   WORD wWindowsMajor;         /* Major windows version             */
  1546.   WORD wWindowsMinor;         /* Minor windows version             */
  1547.   WORD fDosShell;             /* DOS Shell active flag             */
  1548.   WinVerDetect (&wWindowsType, &wWindowsMajor, &wWindowsMinor, &fDosShell);
  1549.   if (wWindowsType == WIN_STANDARD_MODE || wWindowsType == WIN_ENHANCED_MODE)
  1550.     ProceduralLangChk (argc, argv, FALSE);
  1551.   else
  1552.     ProceduralLangChk (argc, argv, TRUE);
  1553.   if (argc != 1 && argv[1][0] != '/')
  1554.     {
  1555.       pszReportFilename = argv[1];
  1556.       /* Set variable for report only */
  1557.       fReportOnly = TRUE;
  1558.       fReportFlag = TRUE;
  1559.       return (FALSE);
  1560.     }
  1561.   if ((argc == 2 || argc == 3)     &&
  1562.       argv[1][0] == '/'            &&
  1563.       toupper (argv[1][1]) == 'S')
  1564.     {
  1565.       if (argc == 3)
  1566.         pszReportFilename = argv[2];
  1567.       else
  1568.         pszReportFilename = pszCon;
  1569.       /* Set variable for report only */
  1570.       fReportOnly   = TRUE;
  1571.       fReportFlag   = TRUE;
  1572.       fSummaryOnly  = TRUE;
  1573.       wReportIndent = 0;
  1574.       return (FALSE);
  1575.     }
  1576.   else
  1577.     {
  1578.       CmdLineHelp();
  1579.       return (TRUE);
  1580.     }
  1581. }
  1582. #endif /* CW_INCLUDED */
  1583. /********************************************************************
  1584.  * CmdLineHelp - Displays command line arguments on screen
  1585.  *
  1586.  * Returns: Void.
  1587.  ********************************************************************/
  1588. VOID CmdLineHelp (VOID)
  1589. {
  1590.   WORD i = 0;   /* Variable for looping though the strings */
  1591.   while (paszCommandLineHelp[i])
  1592.     PutString (paszCommandLineHelp[i++]);
  1593. }
  1594. /********************************************************************
  1595.  * SetMiscGlobals - Set some global variables (DOS version, etc).
  1596.  *
  1597.  * Returns: TRUE if an error occured
  1598.  ********************************************************************/
  1599. BOOL SetMiscGlobals (PSZ pszPath)
  1600. {
  1601.   union REGS inregs, outregs;   /* Used for calling DOS interrupts   */
  1602.   BOOL fReturnValue;            /* Return value from GetSwIntTable() */
  1603.   WORD wWindowsType;          /* Windows type                      */
  1604.   WORD wWindowsMajor;         /* Major windows version             */
  1605.   WORD wWindowsMinor;         /* Minor windows version             */
  1606.   WORD fDosShell;             /* DOS Shell active flag             */
  1607.   /* Determine the DOS version */
  1608.   inregs.h.ah = 0x30;
  1609.   inregs.h.al = 0x00;
  1610.   int86 (0x21, &inregs, &outregs);
  1611.   /* Set the global variable for the DOS version */
  1612.   wDosMajor = outregs.h.al;
  1613.   wDosMinor = outregs.h.ah;
  1614.   /* Display error message if appropriate */
  1615.   if (outregs.h.al < 3)
  1616.     {
  1617.       PutString ("Microsoft Diagnostics requires MS-DOS or PC-DOS v3.00 or later.");
  1618.       return (TRUE);
  1619.     }
  1620.   pszPathToProgram = pszPath;
  1621.   fReturnValue = GetSwIntTable();
  1622.   if (fReturnValue)
  1623.     return (fReturnValue);
  1624.   /* Set MSD's DOS critical error handling routine */
  1625.   _harderr (CriticalErrorHandler);
  1626. #if CW_INCLUDED
  1627.   /* Poll the keyboard in the CW interface */
  1628.   fPollKeyboard = TRUE;
  1629. #endif
  1630.   MemoryFence();
  1631.   /* Set the flag indiciating that Windows is running */
  1632.   WinVerDetect (&wWindowsType, &wWindowsMajor, &wWindowsMinor, &fDosShell);
  1633.   fWindowsRunning = (wWindowsType) ? TRUE : FALSE;
  1634.   return (FALSE);
  1635. }
  1636. /**********************************************************************
  1637.  * MemoryFence - Enough memory has to be free for MSD to run to get
  1638.  *               beyond this routine.
  1639.  **********************************************************************/
  1640. VOID MemoryFence (VOID)
  1641. {
  1642.   union REGS regs;
  1643.   long segment_prefix, lConv_Mem;
  1644.   int86(0x12, &regs, &regs);
  1645.   lConv_Mem = regs.x.ax * 1024L;
  1646.   segment_prefix = 0L;
  1647.   segment_prefix = segment_prefix + ((long)(_psp) * 0x10);
  1648.   /* Are there enough bytes free */
  1649.   if (lConv_Mem - segment_prefix < 340000L)
  1650.     {
  1651.       puts (pszInsufMemory);
  1652.       exit (1);
  1653.     }
  1654. }
  1655. VOID InitParm1 (PSZ pszParm1)
  1656. {
  1657.   WORD  i;
  1658.   UCHAR uchXorMask = 0x5F;
  1659.   static UCHAR szText1[] =
  1660.     {
  1661.       128, 191, 239, 232, 215, 174, 243, 249, 243, 175, 212, 154, 112,
  1662.       139, 136, 132, 194, 174, 141, 134, 148, 136, 155, 134, 140, 159,
  1663.       204, 169, 135, 142, 151, 159, 157, 128, 128, 156, 149, 132, 216,
  1664.       169, 136, 148, 155, 143, 159, 146, 180, 226, 247, 228, 184, 206,
  1665.       232, 242, 232, 233, 251, 241, 128, 227, 219, 153, 174, 175, 134,
  1666.       135, 136, 251, 197, 210, 140, 229, 207, 221, 192, 212, 192, 147,
  1667.       148, 149, 150, 151, 144, 235, 213, 194, 244, 220, 158, 159, 224,
  1668.       225, 180, 242, 234, 245, 230, 177, 249, 231, 251, 235, 186, 255,
  1669.       224, 255, 249, 219, 242, 243, 244, 159, 185, 178, 180, 249, 145,
  1670.       169, 181, 174, 170, 255, 192, 193, 194, 195, 204, 175, 137, 130,
  1671.       132, 162, 152, 203, 204, 205, 152, 222, 222, 193, 210, 133, 197,
  1672.       219, 199, 222, 242, 217, 218, 219, 176, 156, 140, 141, 237, 181,
  1673.       193, 248, 247, 253, 186, 187, 188, 189, 190, 183, 236, 192, 213,
  1674.       209, 193, 203, 197, 240, 136, 223, 155, 133, 156, 141, 216, 158,
  1675.       158, 128, 155, 185, 148, 149, 150, 253, 215, 209, 212, 155, 241,
  1676.       200, 208, 203, 178, 180, 175, 227, 228, 229, 238, 141, 167, 161,
  1677.       164, 134, 185, 163, 238, 239, 166, 224, 252, 227, 253, 223, 246,
  1678.       247, 248, 141, 179, 182, 252, 159, 172, 186, 151, 132, 144, 195,
  1679.       196, 197, 198, 199, 192, 189, 131, 134, 174, 159, 206, 207, 208,
  1680.       209, 132, 194, 218, 197, 223, 253, 216, 217, 218, 177, 147, 149,
  1681.       144, 223, 214, 224, 242, 254, 255, 185, 186, 187, 188, 189, 182,
  1682.       213, 207, 201, 204, 225, 209, 193, 134, 135, 222, 152, 132, 155,
  1683.       133, 167, 142, 143, 144, 235, 199, 209, 213, 220, 196, 151, 249,
  1684.       215, 201, 218, 206, 212, 158, 159, 232, 155, 183, 161, 165, 172,
  1685.       180, 134, 232, 233, 188, 250, 226, 252, 231, 197, 240, 241, 242,
  1686.       151, 187, 187, 246, 154, 177, 181, 182, 190, 174, 253, 254, 255,
  1687.       192, 193, 202, 167, 139, 139, 171, 142, 132, 201, 202, 203, 154,
  1688.       220, 192, 222, 217, 251, 248, 163, 134, 154, 145, 133, 153, 148,
  1689.       218, 182, 157, 147, 159, 152, 241, 231, 172, 157, 184, 185, 186,
  1690.       207, 245, 240, 190, 221, 210, 196, 213, 198, 214, 133, 134, 135,
  1691.       136, 137, 130, 255, 197, 192, 236, 221, 144, 145, 146, 147, 194,
  1692.       132, 152, 135, 152, 207, 139, 149, 141, 157, 200, 141, 238, 241,
  1693.       235, 201, 0
  1694.     };
  1695.   if (_bios_keybrd (_KEYBRD_SHIFTSTATUS) & 114 == 114)
  1696.     {
  1697.       for (i = 0; i < 10 &&
  1698.            ((CHAR) pszParm1[i] == (CHAR) (szText1[9 - i] & (UCHAR) 0x7F));
  1699.            ++i)
  1700.         ;
  1701.       if (i != 10)
  1702.         return;
  1703.       for (i = 13; szText1[i] != 0; ++i)
  1704.         {
  1705.           putchar ((szText1[i] ^ uchXorMask) & 0x7f);
  1706.           uchXorMask = (UCHAR) ((++uchXorMask > 0x7F) ? 0x14 : uchXorMask);
  1707.         }
  1708.       exit (0);
  1709.     }
  1710.   else if (pszParm1[0] == 0x2F)
  1711.     {
  1712.       WORD wValue = (WORD) toupper(pszParm1[1]) + (WORD) szText1[0127];
  1713.       
  1714.       if ((wValue & 0x00FF) == 53)
  1715.         {
  1716.           wMaxRecords = 0;
  1717.           pszParm1[1] = '';
  1718.         }
  1719.     }
  1720. }
  1721. #if CW_INCLUDED
  1722. /*********************************************************************
  1723.  * DisplayStatus - Displays text on the status line.
  1724.  *
  1725.  * wNumber - String number to be displayed.
  1726.  *********************************************************************/
  1727. VOID DisplayStatus (WORD wNumber)
  1728. {
  1729.   SendMessage (pwndStatusLine, WM_NEW_STATUS_LINE_STRING, wNumber, NULL);
  1730. }
  1731. /*********************************************************************
  1732.  * ShowStatus - Displays text on the status line.
  1733.  *
  1734.  * pszMessage - Message to be displayed.
  1735.  *********************************************************************/
  1736. VOID ShowStatus (PSZ pszMessage)
  1737. {
  1738.   /* Display the string */
  1739.   SendMessage (pwndStatusLine, WM_NEW_STATUS_LINE_STRING,
  1740.                0, (DWORD) ((WORD) (pszMessage)));
  1741. }
  1742. #endif /* CW_INCLUDED */
  1743. #if HEAP_DEBUG
  1744. /*********************************************************************
  1745.  * HeapCheck - Checks the status of the heap -- malloc's memory
  1746.  *             handling area.  Displays an error message when a
  1747.  *             problem occurs.
  1748.  *
  1749.  * pszDescription - Description string passed to HeapCheck, usually
  1750.  *                  describing the routine that called HeapCheck.
  1751.  *********************************************************************/
  1752. VOID HeapCheck (PSZ pszDescription)
  1753. {
  1754.   INT iStatus;            /* Status of _heap... calls */
  1755.   _HEAPINFO hi;           /* Heap Info structure */
  1756.   /* Perform an initial check of the heap */
  1757.   if ((iStatus = _heapchk()) == _HEAPEMPTY)
  1758.     return;
  1759.   /* If the status wasn't OK, show the error */
  1760.   if (iStatus != _HEAPOK)
  1761.     {
  1762.       HeapShowStatus (iStatus, pszDescription);
  1763.       return;
  1764.     }
  1765.   /* Because _heapchk() is not a complete check, I have to walk */
  1766.   /*   through the entire heap.                                 */
  1767.   /* Set hi._pentry to NULL to start walking the heap.          */
  1768.   hi._pentry = NULL;
  1769.   while ((iStatus = _heapwalk (&hi)) == _HEAPOK)
  1770.     ;
  1771.   /* See if the final status warrants a look */
  1772.   HeapShowStatus (iStatus, pszDescription);
  1773. }
  1774. /*********************************************************************
  1775.  * HeapShowStatus - Displays an error message if iStatus is an
  1776.  *                  error condition.
  1777.  *
  1778.  * int iStatus    - Status value to report
  1779.  *
  1780.  * pszDescription - Description string passed to HeapCheck, usually
  1781.  *                  describing the routine that called HeapCheck.
  1782.  *********************************************************************/
  1783. VOID HeapShowStatus (INT iStatus, PSZ pszDescription)
  1784. {
  1785.   PSZ pszErrorMsg = NULL;      /* Pointer to error message, NULL   */
  1786.                                /*   if there is no error to report */
  1787.   switch (iStatus)
  1788.     {
  1789.       case _HEAPBADPTR:
  1790.         pszErrorMsg = "ERROR - bad pointer to heap";
  1791.         break;
  1792.       case _HEAPBADBEGIN:
  1793.         pszErrorMsg = "ERROR - bad start of heap";
  1794.         break;
  1795.       case _HEAPBADNODE:
  1796.         pszErrorMsg = "ERROR - bad node in heap";
  1797.         break;
  1798.     }
  1799.   if (pszErrorMsg != NULL)
  1800.     ShowError (MB_OK | 0x8000, pszErrorMsg, pszDescription, "");
  1801. }
  1802. #endif /* HEAP_DEBUG */
  1803. /*********************************************************************
  1804.  * BiosStringOutAt - Outputs a string at a specific screen location
  1805.  *                   through the BIOS routines.
  1806.  *
  1807.  * pszString - String to output.
  1808.  * wAttrib   - Attribute for text output.
  1809.  * wLine     - Line number for output.
  1810.  * wCol      - Column number for output.
  1811.  *********************************************************************/
  1812. VOID BiosStringOutAt (PSZ pszString, WORD wAttrib, WORD wX, WORD wY)
  1813. {
  1814.   BiosLocate (wX, wY);
  1815.   BiosStringOut (pszString, wAttrib);
  1816. }
  1817. /*********************************************************************
  1818.  * BiosStringOut - Outputs a string through the BIOS routines.
  1819.  *
  1820.  * pszString - String to output.
  1821.  * wAttrib   - Attribute for text output.
  1822.  *********************************************************************/
  1823. VOID BiosStringOut (PSZ pszString, WORD wAttrib)
  1824. {
  1825.   while (*pszString)
  1826.     {
  1827.       BiosCharOut (*(pszString++), wAttrib, 1);
  1828.     }
  1829. }
  1830. /*********************************************************************
  1831.  * BiosCharOutAt - Outputs a character at a specific screen location
  1832.  *                 through the BIOS routines.
  1833.  *
  1834.  * wChar   - Character to output.
  1835.  * wAttrib - Attribute for the character.
  1836.  * wCopies - Number of copies to make for this character.
  1837.  * wLine   - Line number for output.
  1838.  * wCol    - Column number for output.
  1839.  *********************************************************************/
  1840. VOID BiosCharOutAt (WORD wChar,
  1841.                     WORD wAttrib,
  1842.                     WORD wCopies,
  1843.                     WORD wX,
  1844.                     WORD wY)
  1845. {
  1846.   BiosLocate (wX, wY);
  1847.   BiosCharOut (wChar, wAttrib, wCopies);
  1848. }
  1849. WORD wBiosX = 0;
  1850. WORD wBiosY = 0;
  1851. /*********************************************************************
  1852.  * BiosCharOut - Outputs a character throught the BIOS routines.
  1853.  *
  1854.  * wChar   - Character to output.
  1855.  * wAttrib - Attribute for the character.
  1856.  * wCopies - Number of copies to make for this character.
  1857.  *********************************************************************/
  1858. VOID BiosCharOut (WORD wChar, WORD wAttrib, WORD wCopies)
  1859. {
  1860.   union REGS regs;              /* Registers for int86 call */
  1861.   /* Set cursor position */
  1862.   regs.h.ah = 0x09;
  1863.   regs.h.al = (BYTE) wChar;
  1864.   regs.h.bh = 0;
  1865.   regs.h.bl = (BYTE) wAttrib;
  1866.   regs.x.cx = wCopies;
  1867.   int86 (0x10, &regs, &regs);
  1868.   /* Move the cursor */
  1869.   BiosLocate (wBiosX + wCopies, wBiosY);
  1870. }
  1871. /*********************************************************************
  1872.  * BiosLocate - Moves cursor to a specific location.
  1873.  *
  1874.  * wLine     - Line number for cursor.
  1875.  * wCol      - Column number for cursor.
  1876.  *********************************************************************/
  1877. VOID BiosLocate (WORD wX, WORD wY)
  1878. {
  1879.   union REGS regs;              /* Registers for int86 call */
  1880.   /* Set cursor position */
  1881.   regs.h.ah = 2;
  1882.   regs.h.bh = 0;
  1883.   regs.h.dl = (BYTE) wX;
  1884.   regs.h.dh = (BYTE) wY;
  1885.   int86 (0x10, &regs, &regs);
  1886.   /* Make the new location available */
  1887.   wBiosX = wX;
  1888.   wBiosY = wY;
  1889. }
  1890. /*********************************************************************
  1891.  * BiosClearScreen - Clears the screen using BIOS routines.
  1892.  *
  1893.  * wAttrib - Attribute for the cleared screen.
  1894.  *********************************************************************/
  1895. VOID BiosClearScreen (WORD wAttrib)
  1896. {
  1897.   WORD wNmbrLines;              /* Screen height in lines */
  1898.   WORD wNmbrCols;               /* Screen height in lines */
  1899.   union REGS inregs, outregs;   /* Registers for int86 calls */
  1900.   {
  1901.     /* The following interrupt gets the display mode in AL, the     */
  1902.     /*   number of columns in AH, and the active video display page */
  1903.     /*   in BH as mentioned on pg 196 of the PC SourceBook -- for   */
  1904.     /*   ALL monitor types                                          */
  1905.     inregs.h.ah = 0x0F;
  1906.     int86 (0x10, &inregs, &outregs);
  1907.     wNmbrCols = outregs.h.ah - 1;
  1908.   }
  1909.   {
  1910.     /* Set the the number of rows on the display */
  1911.     BYTE FAR * fbByte = NULL;  /* Far pointer to a byte */
  1912.     /* Point to the location of the number of rows on the display */
  1913.     fbByte = (BYTE FAR *) 0x00400084;
  1914.     if (*fbByte == 42 || *fbByte == 49)
  1915.       wNmbrLines = (WORD) (*fbByte);
  1916.     else
  1917.       wNmbrLines = 24;
  1918.   }
  1919.   /* Scroll the window */
  1920.   BiosScrollUp (0, 0, wNmbrCols, wNmbrLines, wAttrib, wNmbrLines);
  1921.   /* Reset the cursor location */
  1922.   BiosLocate (0, 0);
  1923. }
  1924. /*********************************************************************
  1925.  * BiosScrollUp - Scrolls a "window" up.
  1926.  *
  1927.  * wX1, wY1   - Upper left X,Y coodinates of box.
  1928.  * wX2, wY2   - Lower Right X,Y coodinates of box.
  1929.  * wAttrib    - Attribute for the new lines.
  1930.  * wNmbrLines - Number of lines to scroll.
  1931.  *********************************************************************/
  1932. VOID BiosScrollUp (WORD wX1, WORD wY1,
  1933.                    WORD wX2, WORD wY2,
  1934.                    WORD wAttrib,
  1935.                    WORD wNmbrLines)
  1936. {
  1937.   union REGS regs;              /* Registers for int86 call */
  1938.   /* Scroll the window */
  1939.   regs.h.ah = 0x06;
  1940.   regs.h.al = (BYTE) wNmbrLines;
  1941.   regs.h.bh = (BYTE) wAttrib;
  1942.   regs.h.ch = (BYTE) wY1;
  1943.   regs.h.cl = (BYTE) wX1;
  1944.   regs.h.dh = (BYTE) wY2;
  1945.   regs.h.dl = (BYTE) wX2;
  1946.   int86 (0x10, &regs, &regs);
  1947. }
  1948. /*********************************************************************
  1949.  * BiosDrawFilledBox - Draws a filled in box on the screen.
  1950.  *
  1951.  * wX1, wY1        - Upper left X,Y coodinates of box.
  1952.  * wX2, wY2        - Lower Right X,Y coodinates of box.
  1953.  * wBorderAttrib   - Attribute for box border.
  1954.  * wInteriorAttrib - Attribute for box interior.
  1955.  *********************************************************************/
  1956. VOID BiosDrawFilledBox (WORD wX1, WORD wY1,
  1957.                         WORD wX2, WORD wY2,
  1958.                         WORD wBorderAttrib,
  1959.                         WORD wInteriorAttrib)
  1960. {
  1961.   /* Don't draw the box if it is too small to draw */
  1962.   if (wX1 == wX2 || wY1 == wY2)
  1963.     return;
  1964.   /* Draw the box */
  1965.   BiosDrawBox (wX1, wY1, wX2, wY2, wBorderAttrib);
  1966.   /* Adjust the coodinates to point inside the box, then */
  1967.   /*   check to see if there is any room to scroll       */
  1968.   if (++wX1 != --wX2 && ++wY1 != --wY2)
  1969.     {
  1970.       BiosScrollUp (wX1, wY1, wX2, wY2, wInteriorAttrib, 0);
  1971.     }
  1972. }
  1973. /*********************************************************************
  1974.  * BiosDrawBox - Draws a box on the screen.
  1975.  *
  1976.  * wX1, wY1  - Upper left X,Y coodinates of box.
  1977.  * wX2, wY2  - Lower Right X,Y coodinates of box.
  1978.  * wAttrib   - Attribute for box border.
  1979.  *********************************************************************/
  1980. VOID BiosDrawBox (WORD wX1, WORD wY1,
  1981.                   WORD wX2, WORD wY2,
  1982.                   WORD wAttrib)
  1983. {
  1984.   WORD i;           /* Looping variable                */
  1985.   INT  iNmbrChars;  /* Number of characters to display */
  1986.   /* Don't draw the box if it is too small to draw */
  1987.   if (wX1 == wX2 || wY1 == wY2)
  1988.     return;
  1989.   /* Draw the top */
  1990.   /* Upper left corner */
  1991.   BiosCharOutAt (boxInfoBox.chTopLeftCorner, wAttrib, 1, wX1, wY1);
  1992.   /* Display the top bar */
  1993.   iNmbrChars = wX2 - wX1 - 1;
  1994.   if (iNmbrChars > 0)
  1995.     BiosCharOut (boxInfoBox.chTopSide, wAttrib, iNmbrChars);
  1996.   /* Upper right corner */
  1997.   BiosCharOut (boxInfoBox.chTopRightCorner, wAttrib, 1);
  1998.   /* Draw the sides */
  1999.   for (i = wY1 + 1; i < wY2; ++i)
  2000.     {
  2001.       BiosCharOutAt (boxInfoBox.chLeftSide, wAttrib, 1, wX1, i);
  2002.       BiosCharOutAt (boxInfoBox.chRightSide, wAttrib, 1, wX2, i);
  2003.       /* Shadow on right edge */
  2004.       BiosCharOut (' ', 0x00, 2);
  2005.     }
  2006.   /* Draw the bottom */
  2007.   /* Bottom left corner */
  2008.   BiosCharOutAt (boxInfoBox.chBottomLeftCorner, wAttrib, 1, wX1, wY2);
  2009.   /* Display the bottom bar */
  2010.   if (iNmbrChars > 0)
  2011.     BiosCharOut (boxInfoBox.chBottomSide, wAttrib, iNmbrChars);
  2012.   /* Bottom right corner */
  2013.   BiosCharOut (boxInfoBox.chBottomRightCorner, wAttrib, 1);
  2014.   /* Shadow on right edge */
  2015.   BiosCharOut (' ', 0x00, 2);
  2016.   /* Shadow across the bottom */
  2017.   BiosCharOutAt (' ', 0x00, iNmbrChars + 2, wX1 + 2, wY2 + 1);
  2018. }