home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c081_7 / 2.ddi / WEXAMPLE.ZIP / FFIND.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-13  |  30.6 KB  |  924 lines

  1. // Borland C++ - (C) Copyright 1991 by Borland International
  2.  
  3. //*******************************************************************
  4. //
  5. // program - Ffind.c
  6. // purpose - a Windows program to find files on system drives.
  7. //
  8. //*******************************************************************
  9.  
  10. #include <windows.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #include <bios.h>
  16. #include <ctype.h>
  17. #include <io.h>
  18. #include <dos.h>
  19. #include <dir.h>
  20.  
  21. #include "ffind.h"
  22.  
  23. #define MAX_QRT_LEN 100
  24.  
  25. // data initialized by first instance
  26. typedef struct tagSETUPDATA
  27.   {
  28.     char   szAppName[10]; // name of application
  29.   } SETUPDATA;
  30.  
  31. SETUPDATA SetUpData;
  32.  
  33. // Data that can be referenced throughout the
  34. // program but not passed to other instances
  35.  
  36. HANDLE    hInst;                              // hInstance of application
  37. HWND      hWndMain;                           // hWnd of main window
  38. //char      szAppName[10];                      // name of application
  39.  
  40. char      qrtxt[MAX_QRT_LEN];                 // dialog input string
  41.  
  42. char      file_name_pattern[MAX_QRT_LEN];     // file name search pattern
  43. int       file_count;                         // count of files found
  44.  
  45. int       xChar, yChar, yCharnl;              // character size
  46. int       xClient, yClient;                   // client window size
  47.  
  48. LOGFONT   cursfont;                           // font structure
  49. HANDLE    holdsfont;                          // handle of original font
  50. HANDLE    hnewsfont;                          // handle of new fixed font
  51.  
  52. HANDLE    hdlgr;                              // handle of dialog resource
  53.  
  54. int       ndrives;                            // number of drives in system
  55. char      fdrives[10];                        // letters of floppy drives
  56. char      hdrives[30];                        // letters of hard drives
  57.  
  58. FARPROC   lpModelessProc;                     // pointer to proc for modeless box
  59. HWND      hQryDlgBox;                         // handle of modeless dialog box
  60.  
  61. // function prototypes
  62.  
  63. int      PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  64.                         LPSTR lpszCmdLine, int cmdShow);
  65.  
  66. void            InitFfind(HANDLE hInstance, HANDLE hPrevInstance,
  67.                           LPSTR lpszCmdLine, int cmdShow);
  68. void            InitFfindFirst(HANDLE hInstance);
  69. void            InitFfindAdded(HANDLE hPrevInstance);
  70. void            InitFfindEvery(HANDLE hInstance, int cmdShow);
  71. void            CloseFfind(void);
  72.  
  73. long FAR PASCAL FfindWndProc(HWND hWnd, WORD message,
  74.                              WORD wParam, LONG lParam);
  75.  
  76. void            InitMainDlg(HWND hWnd);
  77. BOOL FAR PASCAL MainDlgBoxProc(HWND hDlg, WORD message,
  78.                                WORD wParam, LONG lParam);
  79.  
  80. int             FindFile(char *drives, char *pattern);
  81. int             DoADir(char *patternp, char *patternn, char *include);
  82. int             FnMatch(char *pat, char *name);
  83. void            FindDrives(char *fdrives, char *hdrives);
  84. char           *FmtEntry(char *buf, char *name, char *patternp,
  85.                          unsigned time, unsigned date, long size);
  86.  
  87. //*******************************************************************
  88. // WinMain - ffind main
  89. //
  90. // paramaters:
  91. //             hInstance     - The instance of this instance of this
  92. //                             application.
  93. //             hPrevInstance - The instance of the previous instance
  94. //                             of this application. This will be 0
  95. //                             if this is the first instance.
  96. //             lpszCmdLine   - A long pointer to the command line that
  97. //                             started this application.
  98. //             cmdShow       - Indicates how the window is to be shown
  99. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  100. //                             SW_MIMIMIZE.
  101. //
  102. // returns:
  103. //             wParam from last message.
  104. //
  105. //*******************************************************************
  106. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  107.                    LPSTR lpszCmdLine, int cmdShow)
  108. {
  109.     MSG   msg;
  110.  
  111.     // Go init this application.
  112.     InitFfind(hInstance, hPrevInstance, lpszCmdLine, cmdShow);
  113.  
  114.     // Get and dispatch messages for this applicaton.
  115.     while (GetMessage(&msg, NULL, 0, 0))
  116.     {
  117.         TranslateMessage(&msg);
  118.         DispatchMessage(&msg);
  119.     }
  120.  
  121.     return(msg.wParam);
  122. }
  123.  
  124. //*******************************************************************
  125.  
  126. //*******************************************************************
  127. // InitFfind - init the ffind application
  128. //
  129. // paramaters:
  130. //             hInstance     - The instance of this instance of this
  131. //                             application.
  132. //             hPrevInstance - The instance of the previous instance
  133. //                             of this application. This will be 0
  134. //                             if this is the first instance.
  135. //             lpszCmdLine   - A long pointer to the command line that
  136. //                             started this application.
  137. //             cmdShow       - Indicates how the window is to be shown
  138. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  139. //                             SW_MIMIMIZE.
  140. //
  141. //*******************************************************************
  142. #pragma argsused
  143. void InitFfind(HANDLE hInstance, HANDLE hPrevInstance,
  144.                LPSTR lpszCmdLine, int cmdShow)
  145. {
  146.     if (!hPrevInstance)              // if no previous instance, this is first
  147.         InitFfindFirst(hInstance);
  148.     else
  149.         InitFfindAdded(hPrevInstance);   // this is not first instance
  150.  
  151.     InitFfindEvery(hInstance, cmdShow);  // initialization for all instances
  152. }
  153.  
  154. //*******************************************************************
  155. // InitFfindFirst - done only for first instance of ffind
  156. //
  157. // paramaters:
  158. //             hInstance     - The instance of this instance of this
  159. //                             application.
  160. //
  161. //*******************************************************************
  162. void InitFfindFirst(HANDLE hInstance)
  163. {
  164.     WNDCLASS wcFfindClass;
  165.  
  166.     // Get string from resource with application name.
  167.     LoadString(hInstance, IDS_NAME, (LPSTR) SetUpData.szAppName, 10);
  168.  
  169.     // Define the window class for this application.
  170.     wcFfindClass.lpszClassName = SetUpData.szAppName;
  171.     wcFfindClass.hInstance     = hInstance;
  172.     wcFfindClass.lpfnWndProc   = FfindWndProc;
  173.     wcFfindClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  174.     wcFfindClass.hIcon         = LoadIcon(hInstance, SetUpData.szAppName);
  175.     wcFfindClass.lpszMenuName  = (LPSTR) NULL;
  176.     wcFfindClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  177.     wcFfindClass.style         = CS_HREDRAW | CS_VREDRAW;
  178.     wcFfindClass.cbClsExtra    = 0;
  179.     wcFfindClass.cbWndExtra    = 0;
  180.  
  181.     // Register the class
  182.     RegisterClass(&wcFfindClass);
  183. }
  184.  
  185. //*******************************************************************
  186. // InitFfindAdded - done only for added instances of ffind
  187. //
  188. // paramaters:
  189. //             hPrevInstance - The instance of the previous instance
  190. //                             of this application.
  191. //
  192. //*******************************************************************
  193. #pragma argsused
  194. void InitFfindAdded(HANDLE hPrevInstance)
  195. {
  196.     // get the results of the initialization of first instance
  197.     GetInstanceData(hPrevInstance, (PSTR) &SetUpData, sizeof(SETUPDATA));
  198. }
  199.  
  200. //*******************************************************************
  201. // InitFfindEvery - done for every instance of ffind
  202. //
  203. // paramaters:
  204. //             hInstance     - The instance of this instance of this
  205. //                             application.
  206. //             cmdShow       - Indicates how the window is to be shown
  207. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  208. //                             SW_MIMIMIZE.
  209. //
  210. //*******************************************************************
  211. #pragma argsused
  212. void InitFfindEvery(HANDLE hInstance, int cmdShow)
  213. {
  214.     TEXTMETRIC tm;
  215.     HDC        hDC;
  216.  
  217.     hInst = hInstance;       // save for use by window procs
  218.  
  219.     // Create applications main window.
  220.     hWndMain = CreateWindow(
  221.                   SetUpData.szAppName,     // window class name
  222.                   SetUpData.szAppName,     // window title
  223.                   WS_BORDER |              // type of window
  224.                     WS_CAPTION |
  225.                     WS_SYSMENU |
  226.                     WS_MINIMIZEBOX,
  227.                   10,                      // x - same as dialog box
  228.                   19,                      // y
  229.                   256,                     // cx
  230.                   123,                     // cy
  231.                   NULL,                    // no parent for this window
  232.                   NULL,                    // use the class menu
  233.                   hInstance,               // who created this window
  234.                   NULL                     // no parms to pass on
  235.                   );
  236.  
  237.     // Get the display context.
  238.     hDC = GetDC(hWndMain);
  239.  
  240.     // Build fixed screen font. Needed to display columinar report.
  241.     cursfont.lfHeight         =  6;
  242.     cursfont.lfWidth          =  6;
  243.     cursfont.lfEscapement     =  0;
  244.     cursfont.lfOrientation    =  0;
  245.     cursfont.lfWeight         =  FW_NORMAL;
  246.     cursfont.lfItalic         =  FALSE;
  247.     cursfont.lfUnderline      =  FALSE;
  248.     cursfont.lfStrikeOut      =  FALSE;
  249.     cursfont.lfCharSet        =  ANSI_CHARSET;
  250.     cursfont.lfOutPrecision   =  OUT_DEFAULT_PRECIS;
  251.     cursfont.lfClipPrecision  =  CLIP_DEFAULT_PRECIS;
  252.     cursfont.lfQuality        =  DEFAULT_QUALITY;
  253.     cursfont.lfPitchAndFamily =  FIXED_PITCH | FF_DONTCARE;
  254.     strcpy(cursfont.lfFaceName, "System");
  255.  
  256.     hnewsfont = CreateFontIndirect((LPLOGFONT) &cursfont);
  257.  
  258.     // Install the font in the current display context.
  259.     holdsfont = SelectObject(hDC, hnewsfont);
  260.  
  261.     // get text metrics for paint
  262.     GetTextMetrics(hDC, &tm);
  263.     xChar = tm.tmAveCharWidth;
  264.     yChar = tm.tmHeight + tm.tmExternalLeading;
  265.     yCharnl = tm.tmHeight;
  266.  
  267.     // Release the display context.
  268.     ReleaseDC(hWndMain, hDC);
  269.  
  270.     // Create a thunk for the main dialog box proc function.
  271.     lpModelessProc = MakeProcInstance(MainDlgBoxProc, hInst);
  272.  
  273.     // Find drive letters for all drives in system.
  274.     // We will only use the hard drives.
  275.     FindDrives(fdrives, hdrives);
  276.     hdrives[9] = 0; // limit drives to max of 9
  277.     ndrives = strlen(hdrives);
  278.  
  279.     InitMainDlg(hWndMain);
  280. }
  281.  
  282. //*******************************************************************
  283. // CloseFfind - done at termination of every instance of ffind
  284. //
  285. //*******************************************************************
  286. void CloseFfind()
  287. {
  288. }
  289.  
  290. //*******************************************************************
  291.  
  292. //*******************************************************************
  293. // FfindWndProc - handles messages for this application
  294. //
  295. // paramaters:
  296. //             hWnd          - The window handle for this message
  297. //             message       - The message number
  298. //             wParam        - The WORD parmater for this message
  299. //             lParam        - The LONG parmater for this message
  300. //
  301. // returns:
  302. //             depends on message.
  303. //
  304. //*******************************************************************
  305. long FAR PASCAL FfindWndProc(HWND hWnd, WORD message,
  306.                              WORD wParam, LONG lParam)
  307. {
  308.     switch (message)
  309.     {
  310.         case WM_MOVE:
  311.             // Move the dialog box on top of our main window every
  312.             // time the main window moves.
  313.             if (IsWindow(hQryDlgBox))
  314.                 SendMessage(hQryDlgBox, message, wParam, lParam);
  315.             break;
  316.  
  317.         case WM_SETFOCUS:
  318.             // Always set the input focus to the dialog box.
  319.             if (IsWindow(hQryDlgBox))
  320.                 SendMessage(hQryDlgBox, message, wParam, lParam);
  321.             break;
  322.  
  323.         case WM_CLOSE:
  324.             // Tell windows to destroy our window.
  325.             DestroyWindow(hWnd);
  326.             break;
  327.  
  328.         case WM_QUERYENDSESSION:
  329.             // If we return TRUE we are saying it's ok with us to end the
  330.             // windows session.
  331.             return((long) TRUE);  // we agree to end session.
  332.  
  333.         case WM_ENDSESSION:
  334.             // If wParam is not zero, it meany every application said ok
  335.             // to WM_QUERYENDSESSION messages, so we are really ending.
  336.             if (wParam)           // if all apps aggreed to end session.
  337.                 CloseFfind();     // This is the end. We will not get a
  338.                                    // WM_DESTROY message on end session.
  339.             break;
  340.  
  341.         case WM_DESTROY:
  342.             // This is the end if we were closed by a DestroyWindow call.
  343.             CloseFfind();
  344.             PostQuitMessage(0);
  345.             break;
  346.  
  347.         default:
  348.             return(DefWindowProc(hWnd, message, wParam, lParam));
  349.     }
  350.  
  351.     return(0L);
  352. }
  353.  
  354. //*******************************************************************
  355.  
  356. //*******************************************************************
  357. // InitMainDlg - put up modeless dialog box
  358. //
  359. // paramaters:
  360. //             hWnd          - The window handle of the caller
  361. //
  362. //*******************************************************************
  363. void InitMainDlg(HWND hWnd)
  364. {
  365.     // This structure describes the fixed portion at the begining of a
  366.     // dialog template. The part we are going to modify is dtItemCount
  367.     // to cause the proper number of drive selector boxes to display.
  368.     typedef struct tagDLGTEMPLATE
  369.     {
  370.         long dtStyle;
  371.         BYTE dtItemCount;
  372.         int  dtX;
  373.         int  dtY;
  374.         int  dtCX;
  375.         int  dtCY;
  376.         char dtResourceName[1];
  377.     }   DLGTEMPLATE;
  378.     DLGTEMPLATE FAR *dltp;
  379.  
  380.     // Modifying dialog box parms on the fly.
  381.  
  382.     // Load the dialog box resource.
  383.     hdlgr = LoadResource(hInst,
  384.                          FindResource(hInst,
  385.                                       MAKEINTRESOURCE(MAIN),
  386.                                       RT_DIALOG));
  387.  
  388.     if (hdlgr)
  389.     {
  390.         // Lock the resource so we have a pointer to it.
  391.         dltp = (DLGTEMPLATE FAR *) LockResource(hdlgr);
  392.         if (dltp)
  393.         {
  394.             // Change the number of items to display. The drive boxes are
  395.             // defined last so we can truncate the ones not needed.
  396.             dltp->dtItemCount = (BYTE) (ndrives + QX_DRV1 - QX_1);
  397.  
  398.             // Create the dialog box. Its proc is the next function down.
  399.             if (!CreateDialogIndirect(hInst,
  400.                                       (LPSTR) dltp,
  401.                                       hWnd,
  402.                                       lpModelessProc))
  403.             {
  404.                 // Unlock dialog resource we locked above.
  405.                 UnlockResource(hdlgr);
  406.  
  407.                 // Free it.
  408.                 FreeResource(hdlgr);
  409.  
  410.                 // Zero handle to it.
  411.                 hdlgr = 0;
  412.             }
  413.         }
  414.     }
  415. }
  416.  
  417. //*******************************************************************
  418. // MainDlgBoxProc - handle Main dialog messages (modeless)
  419. //
  420. // This is a modeless dialog box procedure that controls this
  421. // entire application.
  422. //
  423. // paramaters:
  424. //             hDlg          - The window handle for this message
  425. //             message       - The message number
  426. //             wParam        - The WORD parmater for this message
  427. //             lParam        - The LONG parmater for this message
  428. //
  429. //*******************************************************************
  430. #pragma argsused
  431. BOOL FAR PASCAL MainDlgBoxProc(HWND hDlg, WORD message,
  432.                                WORD wParam, LONG lParam)
  433. {
  434.     static HWND   hlistwnd;
  435.     static RECT   wrect;
  436.  
  437.     int           x, y, w, h, i, rc;
  438.     char         *cp, *cpd, tmp[30], sdrives[30];
  439.     HANDLE        hCursor;
  440.  
  441.     switch (message)
  442.     {
  443.         case WM_INITDIALOG:
  444.             // Save the handle of this proc for use by main window proc.
  445.             hQryDlgBox = hDlg;
  446.  
  447.             // Set names of drives in drive box text.
  448.             cp = hdrives;
  449.             for (i = 0; i < ndrives; i++)
  450.             {
  451.                 sprintf(tmp, "%c:", *cp++);
  452.                 SetDlgItemText(hDlg, QX_DRV1 + i, tmp);
  453.             }
  454.  
  455.             // Select the first drive.
  456.             SendMessage(GetDlgItem(hDlg, QX_DRV1), BM_SETCHECK, TRUE, 0L);
  457.  
  458.             // Get position of dialog box window.
  459.             GetWindowRect(hDlg, (LPRECT) &wrect);
  460.             w = wrect.right - wrect.left;
  461.             h = wrect.bottom - wrect.top;
  462.  
  463.             // Move main application window to same position.
  464.             SetWindowPos(hWndMain, hDlg,
  465.                          wrect.left, wrect.top, w, h,
  466.                          0);
  467.  
  468.             // Establish initial value of file name pattern box.
  469.             strcpy(file_name_pattern, "*.*");
  470.             SetDlgItemText(hDlg, QX_PATTERN, file_name_pattern);
  471.             SetFocus(GetDlgItem(hDlg, QX_PATTERN));
  472.  
  473.             // Save handle of list box control because we use it a lot.
  474.             hlistwnd = GetDlgItem(hDlg, QX_LIST);
  475.  
  476.             // Install fixed fonts for those controls that need it.
  477.             SendMessage(GetDlgItem(hDlg, QX_3), WM_SETFONT, hnewsfont, FALSE);
  478.             SendMessage(GetDlgItem(hDlg, QX_LIST), WM_SETFONT, hnewsfont, FALSE);
  479.             SendMessage(GetDlgItem(hDlg, QX_COUNT), WM_SETFONT, hnewsfont, FALSE);
  480.             break;
  481.  
  482.         case WM_MOVE:
  483.             // Always keep this dialog box on top of main window.
  484.             GetWindowRect(hWndMain, (LPRECT) &wrect);
  485.             x = wrect.left;
  486.             y = wrect.top;
  487.             w = wrect.right - wrect.left;
  488.             h = wrect.bottom - wrect.top;
  489.             MoveWindow(hDlg, x, y, w, h, 1);
  490.             break;
  491.  
  492.         case WM_SYSCOMMAND:
  493.             // Pass WM_SYSCOMMAND messages on to main window so both
  494.             // main window and dialog box get iconized, minimized etc.
  495.             // in parallel.
  496.             SendMessage(hWndMain, message, wParam, lParam);
  497.             break;
  498.  
  499.         case WM_COMMAND:
  500.             switch (wParam)
  501.             {
  502.                 case QX_PATTERN:                 // Pattern string
  503.                     GetDlgItemText(hDlg, wParam, qrtxt, MAX_QRT_LEN);
  504.                     break;
  505.  
  506.                 case QX_SEARCH:                  // File button
  507.                     strcpy(file_name_pattern, qrtxt);
  508.  
  509.                     // Build list of selected drives.
  510.                     cp = hdrives;
  511.                     cpd = sdrives;
  512.                     for ( i = 0; i < ndrives; i++)
  513.                     {
  514.                         if (SendMessage(GetDlgItem(hDlg, QX_DRV1 + i), BM_GETCHECK, 0, 0L))
  515.                             *cpd++ = *cp;
  516.                         cp++;
  517.                     }
  518.                     *cpd = 0;
  519.  
  520.                     // Clear any previous list and count.
  521.                     SendMessage(hDlg, WM_COMMAND, QX_CLEARW, 0L);
  522.  
  523.                     // Tell list control not to display till we are done
  524.                     SendDlgItemMessage(hDlg, QX_LIST, WM_SETREDRAW, FALSE, 0L);
  525.  
  526.                     // Load hour-glass cursor.
  527.                     hCursor = LoadCursor(NULL, IDC_WAIT);
  528.                     SetCursor(hCursor);
  529.  
  530.                     // Go find files matching pattern on selected drives.
  531.                     rc = FindFile(sdrives, file_name_pattern);
  532.  
  533.                     // Tell list control ok to redraw itself.
  534.                     SendDlgItemMessage(hDlg, QX_LIST, WM_SETREDRAW, TRUE, 0L);
  535.  
  536.                     // Reload arrow cursor.
  537.                     SetCursor(hCursor);
  538.  
  539.                     // See if out of memory error.
  540.                     if (rc < 0)
  541.                     {
  542.                         MessageBox(hDlg,
  543.                                    "Out of memory",
  544.                                    "--ERROR--",
  545.                                    MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
  546.                     }
  547.  
  548.                     // Show count of files fount.
  549.                     sprintf(tmp, "# %5d", file_count);
  550.                     SetDlgItemText(hDlg, QX_COUNT, tmp);
  551.  
  552.                     // Show list window.
  553.                     InvalidateRect(hlistwnd, NULL, TRUE);
  554.                     UpdateWindow(hlistwnd);
  555.                     break;
  556.  
  557.                 case QX_CLEARW:
  558.                     // Clear list window.
  559.                     SendMessage(hlistwnd, LB_RESETCONTENT, TRUE, 0L);
  560.                     InvalidateRect(hlistwnd, NULL, TRUE);
  561.                     UpdateWindow(hlistwnd);
  562.  
  563.                     // Set count to 0.
  564.                     file_count = 0;
  565.                     sprintf(tmp, "# %5d", file_count);
  566.                     SetDlgItemText(hDlg, QX_COUNT, tmp);
  567.                     break;
  568.  
  569.                 case QX_CANCEL:                  // Cancel button
  570.                     // Tell main application window we want to quit.
  571.                     SendMessage(hWndMain, WM_CLOSE, 0, 0L);
  572.                     break;
  573.  
  574.                 default:
  575.                     break;
  576.             }
  577.             break;
  578.  
  579.         case WM_CLOSE:
  580.             // Unlock dialog resource we locked above.
  581.             UnlockResource(hdlgr);
  582.  
  583.             // Free it.
  584.             FreeResource(hdlgr);
  585.  
  586.             // Zero handle to it.
  587.             hdlgr = 0;
  588.  
  589.             // Zero handle to this dialog window.
  590.             hQryDlgBox = 0;
  591.  
  592.             // Tell main window to close.
  593.             PostMessage(hWndMain, WM_CLOSE, 0, 0L);
  594.  
  595.             // Destroy ourseleves.
  596.             DestroyWindow(hDlg);
  597.             break;
  598.  
  599.         default:
  600.             return FALSE;
  601.     }
  602.  
  603.     return(TRUE);
  604. }
  605.  
  606. //*******************************************************************
  607.  
  608. //*******************************************************************
  609. // FindFile - find files matching a pattern files on specified drives
  610. //
  611. // paramaters:
  612. //             drives   - An array of drive letters to search.
  613. //             pattern  - A file name pattern.
  614. //
  615. // returns:
  616. //             Number of files found matching pattern.
  617. //             If unable to add a name to listbox, number is returned as
  618. //             a negative.
  619. //
  620. //*******************************************************************
  621. FindFile(char *drives, char *pattern)
  622. {
  623.     char     tree[3];
  624.     int      nfiles;
  625.     int      rc;
  626.  
  627.     rc = 0;
  628.     nfiles = 0;
  629.     file_count = 0;
  630.     tree[1] = ':';
  631.     tree[2] = 0;
  632.     while (*drives)
  633.     {
  634.         tree[0] = *drives++;
  635.         nfiles = DoADir(tree, "*.*", pattern);
  636.         if (nfiles >= 0)
  637.             file_count += nfiles;
  638.         else
  639.         {
  640.             file_count -= nfiles;
  641.             rc = -file_count;
  642.             break;
  643.         }
  644.     }
  645.  
  646.     return(rc);
  647. }
  648.  
  649. //*******************************************************************
  650. // DoADir - search a directory for files matching a file name pattern
  651. //          recursivly search sub directories
  652. //
  653. // paramaters:
  654. //             patternp  - A path to search.
  655. //             patternn  - A file name pattern to use to find directories.
  656. //             include   - A file name pattern to use to select files.
  657. //
  658. // returns:
  659. //             Number of files found matching include.
  660. //             If unable to add a name to listbox, number is returned as
  661. //             a negative.
  662. //
  663. //*******************************************************************
  664. int DoADir(char *patternp, char *patternn, char *include)
  665. {
  666.     char          patternw[80];
  667.     char          npatternp[64];
  668.     char          buf[128];
  669.     int           files;
  670.     int           mfiles;
  671.     int           have_subs;
  672.     int           nfiles;
  673.     LONG          lrc;
  674.     struct ffblk  fileinfo;
  675.  
  676.     strcpy(patternw, patternp);
  677.     strcat(patternw, "\\");
  678.  
  679.     strcat(patternw, patternn);
  680.  
  681.     files = 0;
  682.     mfiles = 0;
  683.     have_subs = 0;
  684.  
  685.     if (!findfirst(patternw, &fileinfo, FA_DIREC))
  686.     {
  687.         do
  688.         {
  689.             if (fileinfo.ff_attrib & FA_DIREC)  // subdirectory
  690.             {
  691.                 if (fileinfo.ff_name[0] != '.')  // ignore . and ..
  692.                     have_subs = 1;
  693.             }
  694.             else                              // file
  695.             {
  696.                 files++;
  697.  
  698.                 if (FnMatch(include, fileinfo.ff_name))
  699.                 {
  700.                     mfiles++;
  701.  
  702.                     FmtEntry(buf, fileinfo.ff_name, patternp,
  703.                              fileinfo.ff_ftime, fileinfo.ff_fdate, fileinfo.ff_fsize);
  704.  
  705.                     lrc = SendDlgItemMessage(hQryDlgBox, QX_LIST, LB_ADDSTRING, 0,
  706.                                             (LONG) ((LPSTR) buf));
  707.  
  708.                     if (lrc == LB_ERR || lrc == LB_ERRSPACE)
  709.                         return(-mfiles); // error return
  710.                 }
  711.             }
  712.         }
  713.         while (!findnext(&fileinfo));
  714.     }
  715.  
  716.     if (have_subs)
  717.     {
  718.         if (!findfirst(patternw, &fileinfo, FA_DIREC))
  719.         {
  720.             do
  721.             {
  722.                 if (fileinfo.ff_attrib & FA_DIREC)  // subdirectory
  723.                 {
  724.                     if (fileinfo.ff_name[0] != '.')  // ignore . and ..
  725.                     {
  726.                         strcpy(npatternp, patternp);
  727.                         strcat(npatternp, "\\");
  728.                         strcat(npatternp, fileinfo.ff_name);
  729.  
  730.                         nfiles = DoADir(npatternp, patternn, include);
  731.  
  732.                         if (nfiles >= 0)
  733.                             mfiles += nfiles;
  734.                         else
  735.                         {
  736.                             mfiles -= nfiles;
  737.                             return(-mfiles); // error return
  738.                         }
  739.                     }
  740.                 }
  741.             }
  742.             while (!findnext(&fileinfo));
  743.         }
  744.     }
  745.  
  746.     return(mfiles);
  747. }
  748.  
  749. //*******************************************************************
  750. // FindDrives - find floppy and hard drives in system
  751. //
  752. // paramaters:
  753. //             fdrives - An array to hold floppy drive letters.
  754. //             hdrives - An array to hold hard drive letters.
  755. //
  756. //*******************************************************************
  757. void FindDrives(char *fdrives, char *hdrives)
  758. {
  759.     unsigned int  equip;
  760.     unsigned int  maxflop;
  761.     unsigned int  savedriveno;
  762.     unsigned int  maxdriveno;
  763.     unsigned int  ui;
  764.     unsigned int  driveno;
  765.     int           nfdrives;
  766.     int           nhdrives;
  767.  
  768.     savedriveno = getdisk() + 1;               // save current drive
  769.  
  770.     equip = biosequip();                       // find how many floppys
  771.     maxflop = ((equip >> 6) & 0x03) + 1;
  772.  
  773.     maxdriveno = setdisk(savedriveno - 1);     // find max drive in system
  774.  
  775.     nfdrives = 0;
  776.     nhdrives = 0;
  777.     for (ui = 1; ui <= maxdriveno; ui++)       // for all potential drives
  778.     {
  779.         if ((ui <= maxflop) || (ui >= 3))
  780.         {
  781.             setdisk(ui - 1);                   // set to drive
  782.             driveno = getdisk() + 1;           // get current drive
  783.  
  784.             if (driveno == ui)                 // if set successful
  785.             {
  786.                 if (ui >= 3)                   // C: assumed to be first hard ?
  787.                     hdrives[nhdrives++] = (char) (ui + '@');
  788.                 else if (ui <= maxflop)        // because set to B: successful even if no B:
  789.                     fdrives[nfdrives++] = (char) (ui + '@');
  790.             }
  791.         }
  792.     }
  793.  
  794.     fdrives[nfdrives] = 0;
  795.     hdrives[nhdrives] = 0;
  796.  
  797.     setdisk(savedriveno - 1);                  // reset current drive
  798. }
  799.  
  800. //*******************************************************************
  801.  
  802. //*******************************************************************
  803. // FnMatch - test if a file name matches a file name pattern.
  804. //           handles * and ? wildcard characters.
  805. //
  806. // paramaters:
  807. //             pat   - A file name pattern (ie. xyz?.*)
  808. //             name  - A file name to test against pat (ie. xyz1.c)
  809. //
  810. // returns:
  811. //             1 - if match
  812. //             0 - if not a match
  813. //
  814. //*******************************************************************
  815. FnMatch(char *pat, char *name)
  816. {
  817.     int   match;
  818.     int   ndone;
  819.     char *cpp;
  820.     char *cpn;
  821.  
  822.     cpp = pat;
  823.     cpn = name;
  824.     match = 1;
  825.     ndone = 1;
  826.     while (ndone)
  827.     {
  828.         switch (*cpp)
  829.         {
  830.             case '*':
  831.                 // skip to . or end of pat
  832.                 while (*cpp && *cpp != '.')
  833.                     cpp++;
  834.  
  835.                 // skip to . or end of name
  836.                 while (*cpn && *cpn != '.')
  837.                     cpn++;
  838.                 break;
  839.  
  840.             case '?':
  841.                 cpp++;
  842.                 cpn++;
  843.                 break;
  844.  
  845.             case 0:
  846.                 if (*cpn != 0)
  847.                     match = 0;
  848.                 ndone = 0;
  849.                 break;
  850.  
  851.             default:
  852.                 if (tolower(*cpp) == tolower(*cpn))
  853.                 {
  854.                     cpp++;
  855.                     cpn++;
  856.                 }
  857.                 else
  858.                 {
  859.                     match = 0;
  860.                     ndone = 0;
  861.                 }
  862.                 break;
  863.         }
  864.     }
  865.  
  866.     return(match);
  867. }
  868.  
  869. //*******************************************************************
  870. // FmtEntry - format directory entry for report
  871. //
  872. // paramaters:
  873. //             buf      - A buffer to hold formated directory entry.
  874. //             name     - File name.
  875. //             patternp - Path on which file was found.
  876. //             time     - File time from directory.
  877. //             date     - File data from directory.
  878. //             szie     - File size from directory.
  879. //
  880. // returns:
  881. //             A pointer to buf.
  882. //
  883. //*******************************************************************
  884. char *FmtEntry(char *buf, char *name, char *patternp,
  885.                unsigned time, unsigned date, long size)
  886. {
  887.     char   *cp;
  888.     char    xname[10];
  889.     char    xext[10];
  890.     int     mo, dd, yy, hh, mi, ss;
  891.  
  892.     cp = strchr(name, '.');
  893.     if (cp)
  894.     {
  895.         *cp = 0;
  896.         strcpy(xname, name);
  897.         strcpy(xext, cp + 1);
  898.     }
  899.     else
  900.     {
  901.         strcpy(xname, name);
  902.         strcpy(xext, "");
  903.     }
  904.  
  905.     mo = (date >> 5) & 0x0f;
  906.     dd = date & 0x1f;
  907.     yy = ((date >> 9) & 0x7f) + 80;
  908.     hh = (time >> 11) & 0x1f;
  909.     mi = (time >> 5) & 0x3f;
  910.     ss = (time & 0x1f) * 2;
  911.  
  912.     sprintf(buf, "%-8s.%-3s %7ld %02d/%02d/%02d %02d:%02d:%02d %s",
  913.                   xname,
  914.                   xext,
  915.                   size,
  916.                   mo, dd, yy,
  917.                   hh, mi, ss,
  918.                   patternp);
  919.  
  920.     return(buf);
  921. }
  922.  
  923. //*******************************************************************
  924.