home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / s12412.zip / OSFINDR.C < prev    next >
C/C++ Source or Header  |  1989-06-22  |  30KB  |  996 lines

  1. /*
  2.  * OS/2 PM File Finder Utility - SOURCE CODE
  3.  *
  4.  * LANGUAGE      : Microsoft C5.1
  5.  * MODEL         : small
  6.  * ENVIRONMENT   : Microsoft OS/2 PM SDK
  7.  * STATUS        : operational
  8.  *
  9.  * Adapted from KPW's Windows 2.1 version of 07/20/88.
  10.  *
  11.  * 11/01/88 1.00 - Jerry Weldon - initial creation.
  12.  *
  13.  */
  14.  
  15. #define INCL_DOSPROCESS
  16. #define INCL_DOSNLS
  17. #define INCL_WINWINDOWMGR
  18. #define INCL_WINDIALOGS
  19. #define INCL_WINBUTTONS
  20. #define INCL_WINENTRYFIELDS
  21. #define INCL_WINLISTBOXES
  22. #define INCL_WINMENUS
  23. #define INCL_WINFRAMEMGR
  24. #define INCL_WINSYS
  25. #define INCL_WINPOINTERS
  26. #define INCL_GPIPRIMITIVES
  27. #define INCL_GPILCIDS
  28.  
  29. #include <os2.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32.  
  33. #include "finder.h"
  34.  
  35. /* global variables */
  36. FATTRS      fat;                                  /* font attributes  */
  37.  
  38. /* */
  39.  
  40. /*
  41.  * main( VOID ) : VOID;
  42.  *
  43.  * This function is the system entry point for the application
  44.  * and is responsible for defining the appropriate window 
  45.  * classes and for processing all the messages.  Note how
  46.  * the dialog box manager is responsible for the operation of
  47.  * the file finder window.
  48.  *
  49.  */
  50.  
  51. VOID main( VOID )
  52. {
  53.   HAB         hab;                        /* handle to anchor block   */
  54.   HMQ         hmq;                        /* handle to message queue  */
  55.   HWND        hwnd;                       /* handle to main window    */
  56.   HPOINTER    hptr;                       /* handle to window's icon  */
  57.  
  58.   /* initialize thread & create message queue */
  59.   hab = WinInitialize( 0 );
  60.   hmq = WinCreateMsgQueue( hab, DEFAULT_QUEUE_SIZE );
  61.  
  62.   /* load the main dialog */
  63.   hwnd = WinLoadDlg(
  64.     HWND_DESKTOP,
  65.     HWND_DESKTOP,
  66.     FinderDlgProc,
  67.     NULL,
  68.     ID_FINDER,
  69.     NULL
  70.   );
  71.  
  72.   /* set an icon for the dialog */
  73.   hptr = WinLoadPointer( HWND_DESKTOP, NULL, ID_FINDER );
  74.   WinSendMsg( hwnd, WM_SETICON, (MPARAM)hptr, 0L );
  75.  
  76.   /* process the dialog */
  77.   WinProcessDlg( hwnd );
  78.  
  79.   /* destroy the dialog and its icon */
  80.   WinDestroyWindow( hwnd );
  81.   WinDestroyPointer( hptr );
  82.  
  83.   /* destroy message queue & terminate thread */
  84.   WinDestroyMsgQueue( hmq );
  85.   WinTerminate( hab );
  86. }
  87.  
  88. /* */
  89.  
  90. /*
  91.  * FinderDlgProc( hwnd, usMsg, mp1, mp2 ) : MRESULT;
  92.  *
  93.  *    hwnd          handle to main dialog window
  94.  *    usMsg         message number
  95.  *    mp1           message parameter 1
  96.  *    mp2           message parameter 2
  97.  *
  98.  * This function is responsible for processing all the messages
  99.  * which relate to the file finder dialog box.  This mainly
  100.  * involves the definition and retrieval of the various
  101.  * events generated by the user.
  102.  *
  103.  */
  104.  
  105. MRESULT EXPENTRY FinderDlgProc(
  106.   HWND        hwnd,
  107.   USHORT      usMsg,
  108.   MPARAM      mp1,
  109.   MPARAM      mp2 )
  110. {
  111.   MRESULT     mresRtnVal;                 /* function return value    */
  112.   BOOL        fPassToDef;                 /* pass to def window proc? */
  113.  
  114.   mresRtnVal = FALSE;
  115.   fPassToDef = FALSE;
  116.   
  117.   switch ( usMsg ) {
  118.  
  119.     case WM_INITDLG:
  120.       {
  121.         HWND        hwndSysMenu;          /* system menu handle       */
  122.         USHORT      idSysMenu;            /* system menu id           */
  123.         MENUITEM    miSysMenu;            /* system menu item info    */
  124.         MENUITEM    miAbout;              /* About menu item info     */
  125.         USHORT      usCurDrive;           /* current drive number     */
  126.         ULONG       flDrives;             /* available logical drives */
  127.         CHAR        szDrive[6];           /* temporary drive string   */
  128.         USHORT      iItem;                /* temporary loop variable  */
  129.         USHORT      cszList;              /* # of selected drives     */
  130.         HWND        hwndListBox;          /* handle to list box       */
  131.  
  132.         /* add About item to system menu */
  133.         if ( hwndSysMenu = WinWindowFromID( hwnd, FID_SYSMENU ) ) {
  134.  
  135.           /* get handle of system submenu */
  136.           idSysMenu = SHORT1FROMMR( WinSendMsg( hwndSysMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT( 0 ), 0L ) );
  137.           WinSendMsg( hwndSysMenu, MM_QUERYITEM, MPFROM2SHORT( idSysMenu, FALSE ), MPFROMP( &miSysMenu ) );
  138.           hwndSysMenu = miSysMenu.hwndSubMenu;
  139.  
  140.           /* add menu separator */
  141.           miAbout.iPosition = MIT_END;
  142.           miAbout.afStyle = MIS_SEPARATOR;
  143.           miAbout.afAttribute = 0;
  144.           miAbout.id = 0;
  145.           miAbout.hwndSubMenu = NULL;
  146.           miAbout.hItem = NULL;
  147.           WinSendMsg( hwndSysMenu, MM_INSERTITEM, MPFROMP( &miAbout ), NULL );
  148.  
  149.           /* add About item */
  150.           miAbout.afStyle = MIS_TEXT;
  151.           miAbout.id = IDM_ABOUT;
  152.           WinSendMsg( hwndSysMenu, MM_INSERTITEM, MPFROMP( &miAbout ), MPFROMP( "A~bout..." ) );
  153.  
  154.         }
  155.  
  156.         /* center dialog box on screen */
  157.         CenterPopup( hwnd, HWND_DESKTOP );
  158.         
  159.         /* define search pattern */
  160.         WinSetDlgItemText( hwnd, IDD_PATTERN, "*.*" );
  161.  
  162.         /* initialize drive list */
  163.         DosQCurDisk( &usCurDrive, &flDrives );
  164.         szDrive[0] = '[';
  165.         szDrive[1] = '-';
  166.         szDrive[3] = '-';
  167.         szDrive[4] = ']';
  168.         szDrive[5] = '\0';
  169.         for ( szDrive[2] = 'A'; szDrive[2] <= 'Z'; szDrive[2]++ ) {
  170.           if ( flDrives & 1 )
  171.             WinSendDlgItemMsg(
  172.               hwnd,
  173.               IDD_DRIVES,
  174.               LM_INSERTITEM,
  175.               MPFROMSHORT( LIT_END ),
  176.               MPFROMP( szDrive )
  177.             );
  178.           flDrives >>= 1;
  179.         }
  180.     
  181.         /* select all fixed drives */           
  182.         hwndListBox = WinWindowFromID( hwnd, IDD_DRIVES );
  183.         cszList = SHORT1FROMMR( WinSendMsg(
  184.           hwndListBox,
  185.           LM_QUERYITEMCOUNT,
  186.           0L,
  187.           0L
  188.         ) );
  189.         for ( iItem = 0; iItem < cszList; iItem++ ) {
  190.           WinSendMsg(
  191.             hwndListBox,
  192.             LM_QUERYITEMTEXT,
  193.             MPFROM2SHORT( iItem, sizeof(szDrive) ),
  194.             MPFROMP( szDrive )
  195.           );
  196.           if ( szDrive[2] >= 'C' )
  197.             WinSendMsg(
  198.               hwndListBox,
  199.               LM_SELECTITEM,
  200.               MPFROMSHORT( iItem ),
  201.               MPFROMSHORT( TRUE )
  202.             );
  203.         }
  204.       }
  205.       break;
  206.  
  207.     case WM_CONTROL:
  208.       switch ( SHORT1FROMMP( mp1 ) ) {
  209.  
  210.         case IDD_PATTERN:
  211.           if ( SHORT2FROMMP( mp1 ) == EN_CHANGE ) 
  212.             /* enable/disable search button */
  213.             WinEnableWindow(
  214.               WinWindowFromID( hwnd, IDD_SEARCH ),
  215.               WinQueryWindowTextLength(
  216.                 WinWindowFromID( hwnd, IDD_PATTERN )
  217.               )
  218.             );
  219.           else
  220.             fPassToDef = TRUE;
  221.           break;
  222.  
  223.         case IDD_FILES:
  224.           switch ( SHORT2FROMMP( mp1 ) ) {
  225.  
  226.             case LN_SELECT: /* an item was selected */
  227.               {
  228.                 USHORT      iSelection;     /* selected file index    */
  229.                 CHAR        szFile[64];     /* name of selected file  */
  230.                 USHORT      cchFile;        /* file name length       */
  231.                 BOOL        fExecable;      /* is file executable?    */
  232.  
  233.                 /* get name of selected file */
  234.                 fExecable = FALSE;
  235.                 iSelection = SHORT1FROMMR( WinSendDlgItemMsg(
  236.                   hwnd,
  237.                   IDD_FILES,
  238.                   LM_QUERYSELECTION,
  239.                   MPFROMSHORT( LIT_FIRST ),
  240.                   0L
  241.                 ) );
  242.                 if ( iSelection != LIT_NONE ) {
  243.                   WinSendDlgItemMsg(
  244.                     hwnd,
  245.                     IDD_FILES,
  246.                     LM_QUERYITEMTEXT,
  247.                     MPFROM2SHORT( iSelection, sizeof(szFile) ),
  248.                     MPFROMP( szFile )
  249.                   );
  250.  
  251.                   /* is file executable? */
  252.                   if ( szFile[0] == ' ' ) {
  253.                     cchFile = strlen( strtok( &szFile[2], " " ) );
  254.                     if ( cchFile > 4
  255.                       && strcmp( &szFile[2+cchFile-4], ".EXE" ) == 0 )
  256.                       fExecable = TRUE;
  257.                   }
  258.                 }
  259.  
  260.                 /* if file is executable, enable run button */
  261.                 WinEnableWindow(
  262.                   WinWindowFromID( hwnd, IDD_RUN ),
  263.                   fExecable
  264.                 );
  265.               }
  266.               break;
  267.  
  268.             case LN_ENTER: /* equivalent to run button clicked */
  269.               WinSendDlgItemMsg( hwnd, IDD_RUN, BM_CLICK, 0L, 0L );
  270.               break;
  271.  
  272.             default:
  273.               fPassToDef = TRUE;
  274.               break;
  275.  
  276.           }
  277.           break;
  278.  
  279.         default:
  280.           fPassToDef = TRUE;
  281.           break;
  282.  
  283.       }
  284.       break;
  285.  
  286.     case WM_COMMAND:
  287.       switch ( COMMANDMSG( &usMsg )->cmd ) {
  288.  
  289.         case IDD_SEARCH: /* search using path */
  290.         case DID_OK:
  291.           {
  292.             HPOINTER  hptrOld;          /* handle to old cursor       */
  293.             USHORT    iItem;            /* temporary loop variable    */
  294.             HWND      hwndListBox;      /* handle to list box         */
  295.             BOOL      fContinue;        /* boolean search flag        */
  296.             CHAR      szDrive[8];       /* drive specification string */
  297.             CHAR      szPattern[64];    /* search pattern string      */
  298.             CHAR      szFileSpec[64];   /* file specification string  */
  299.       
  300.             /* disable run button & change cursor to hourglass */
  301.             WinEnableWindow( WinWindowFromID( hwnd, IDD_RUN ), FALSE );
  302.             hptrOld = WinQueryPointer( HWND_DESKTOP );
  303.             WinSetPointer(
  304.               HWND_DESKTOP,
  305.               WinQuerySysPointer( HWND_DESKTOP, SPTR_WAIT, FALSE )
  306.             );
  307.         
  308.             /* retrieve search pattern & erase current file list */
  309.             WinQueryDlgItemText(
  310.               hwnd,
  311.               IDD_PATTERN,
  312.               sizeof(szPattern),
  313.               szPattern
  314.             );
  315.             WinSendDlgItemMsg( hwnd, IDD_FILES, LM_DELETEALL, 0L, 0L );
  316.  
  317.             /* perform search on each selected drive */
  318.             fContinue = TRUE;
  319.             hwndListBox = WinWindowFromID( hwnd, IDD_DRIVES );
  320.             iItem = LIT_FIRST;
  321.             while (
  322.               (iItem = SHORT1FROMMR( WinSendMsg(
  323.                 hwndListBox,
  324.                 LM_QUERYSELECTION,
  325.                 MPFROMSHORT( iItem ),
  326.                 0L ) )) != LIT_NONE
  327.               && fContinue
  328.             ) {
  329.  
  330.               /* define file specification */
  331.               WinSendMsg(
  332.                 hwndListBox,
  333.                 LM_QUERYITEMTEXT,
  334.                 MPFROM2SHORT( iItem, sizeof(szDrive) ),
  335.                 MPFROMP( szDrive )
  336.               );
  337.               sprintf( szFileSpec, "%c:\\%s", szDrive[2], szPattern );
  338.  
  339.               /* create directory listing using pattern */
  340.               fContinue = Directory(
  341.                 szFileSpec,
  342.                 FILE_NORMAL,
  343.                 WinWindowFromID( hwnd, IDD_FILES )
  344.               );
  345.           
  346.             }
  347.         
  348.             /* check for null search operation */
  349.             if ( !WinSendDlgItemMsg(
  350.               hwnd,
  351.               IDD_FILES,
  352.               LM_QUERYITEMCOUNT,
  353.               0L,
  354.               0L
  355.             ) )
  356.               WinMessageBox(
  357.                 HWND_DESKTOP,
  358.                 hwnd,
  359.                 "No files found matching criteria!",
  360.                 "File Finder",
  361.                 0,
  362.                 MB_OK | MB_ICONHAND
  363.               );
  364.           
  365.             /* restore cursor */
  366.             WinSetPointer( HWND_DESKTOP, hptrOld );
  367.           }
  368.           break;
  369.  
  370.         case IDD_RUN:
  371.           {
  372.             USHORT      iSelection;       /* selected file index      */
  373.             CHAR        szFile[64];       /* name of executable file  */
  374.             CHAR        szDir[64];        /* name of directory        */
  375.             CHAR        szPath[64];       /* full path name of file   */
  376.             CHAR        szFail[64];       /* if DosExecPgm fails      */
  377.             RESULTCODES resc;             /* result of child process  */
  378.             USHORT      usErr;            /* error code               */
  379.  
  380.             /* get name of selected file */
  381.             iSelection = SHORT1FROMMR( WinSendDlgItemMsg(
  382.               hwnd,
  383.               IDD_FILES,
  384.               LM_QUERYSELECTION,
  385.               MPFROMSHORT( LIT_FIRST ),
  386.               0L
  387.             ) );
  388.             if ( iSelection != LIT_NONE ) {
  389.               WinSendDlgItemMsg(
  390.                 hwnd,
  391.                 IDD_FILES,
  392.                 LM_QUERYITEMTEXT,
  393.                 MPFROM2SHORT( iSelection, sizeof(szFile) ),
  394.                 MPFROMP( szFile )
  395.               );
  396.  
  397.               /* define full path name */
  398.               do {
  399.                 WinSendDlgItemMsg(
  400.                   hwnd,
  401.                   IDD_FILES,
  402.                   LM_QUERYITEMTEXT,
  403.                   MPFROM2SHORT( --iSelection, sizeof(szDir) ),
  404.                   MPFROMP( szDir )
  405.                 );
  406.               } while ( szDir[0] == ' ' );
  407.               sprintf(
  408.                 szPath,
  409.                 "%s\\%s",
  410.                 szDir,
  411.                 strtok( &szFile[2], " " )
  412.               );
  413.  
  414.               /* run it */
  415.               usErr = DosExecPgm(
  416.                 szFail,
  417.                 sizeof(szFail),
  418.                 EXEC_ASYNC,
  419.                 NULL,
  420.                 NULL,
  421.                 &resc,
  422.                 szPath
  423.               );
  424.               if ( usErr )
  425.                 WinMessageBox(
  426.                   HWND_DESKTOP,
  427.                   hwnd,
  428.                   "Unable to execute file!",
  429.                   "File Finder",
  430.                   0,
  431.                   MB_OK | MB_ICONHAND
  432.                 );
  433.               else
  434.                 WinSendMsg(
  435.                   hwnd,
  436.                   WM_SYSCOMMAND,
  437.                   MPFROMSHORT( SC_MINIMIZE ),
  438.                   MPFROMSHORT( CMDSRC_OTHER )
  439.                 );
  440.             }
  441.           }
  442.           break;
  443.  
  444.         case IDD_QUIT:
  445.           WinDismissDlg( hwnd, TRUE );
  446.           break;
  447.  
  448.         case IDM_ABOUT:
  449.           WinDlgBox( HWND_DESKTOP, hwnd, AboutDlgProc, NULL, IDD_ABOUTDLG, NULL );
  450.           break;
  451.  
  452.         case DID_CANCEL:
  453.           /* don't quit the program when escape key is pressed */
  454.           break;
  455.  
  456.         default:
  457.           fPassToDef = TRUE;
  458.           break;
  459.  
  460.       }
  461.       break;
  462.  
  463.     case WM_MEASUREITEM:
  464.       if ( SHORT1FROMMP( mp1 ) == IDD_FILES ) {
  465.  
  466.         HPS         hps;                  /* handle to window PS      */
  467.         FONTMETRICS afm[14];              /* info of available fonts  */
  468.         LONG        cfm;                  /* # of available fonts     */
  469.         LONG        i;                    /* font index               */
  470.         LONG        lErr;                 /* error code               */
  471.         BOOL        fErr;                 /* error code               */
  472.  
  473.         /* find a monospace font for list boxes */
  474.         hps = WinGetPS( hwnd );
  475.         cfm = 14;
  476.         GpiQueryFonts(
  477.           hps,
  478.           QF_PUBLIC,
  479.           "Courier",
  480.           &cfm,
  481.           (LONG)sizeof(afm[0]),
  482.           afm
  483.         );
  484.         for ( i = 0; i < cfm && afm[i].fsDefn & 0x0001; i++ )
  485.           /* skip proportional fonts */;
  486.  
  487.         /* set up for using it */
  488.         fat.usRecordLength = sizeof(fat);
  489.         fat.fsSelection = afm[i].fsSelection;
  490.         fat.lMatch = afm[i].lMatch;
  491.         strcpy( fat.szFacename, afm[i].szFacename );
  492.         fat.idRegistry = afm[i].idRegistry;
  493.         fat.usCodePage = 850;
  494.         fat.lMaxBaselineExt = afm[i].lMaxBaselineExt;
  495.         fat.lAveCharWidth = afm[i].lAveCharWidth;
  496.         fat.fsType = FATTR_TYPE_FIXED;
  497.         fat.fsFontUse = 0;
  498.         lErr = GpiCreateLogFont( hps, NULL, 1L, &fat );
  499.         fErr = GpiSetCharSet( hps, 1L );
  500.  
  501.         /* return the height of a listbox item */
  502.         mresRtnVal = MRFROMLONG( fat.lMaxBaselineExt+2 );
  503.         WinReleasePS( hps );
  504.  
  505.       }
  506.       break;
  507.  
  508.     case WM_DRAWITEM:
  509.       if ( SHORT1FROMMP( mp1 ) == IDD_FILES ) {
  510.  
  511.         POWNERITEM  poi;                          /* item to be drawn */
  512.         LONG        lErr;                         /* error code       */
  513.         BOOL        fErr;                         /* error code       */
  514.  
  515.         /* change the font to our monospace one if it's not already */
  516.         poi = PVOIDFROMMP( mp2 );
  517.         if ( GpiQueryCharSet( poi->hps ) != 1L ) {
  518.           lErr = GpiCreateLogFont( poi->hps, NULL, 1L, &fat );
  519.           fErr = GpiSetCharSet( poi->hps, 1L );
  520.         }
  521.  
  522.       }
  523.       break;
  524.  
  525.     case WM_MINMAXFRAME:
  526.       {
  527.         PSWP        pswp;                     /* pos change structure */
  528.  
  529.         /* hide list box when minimized so it doesn't overwrite icon */
  530.         pswp = PVOIDFROMMP( mp1 );
  531.         WinShowWindow(
  532.           WinWindowFromID( hwnd, IDD_FILES ),
  533.           !(pswp->fs & SWP_MINIMIZE)
  534.         );
  535.       }
  536.       break;
  537.  
  538.     default:
  539.       fPassToDef = TRUE;
  540.       break;
  541.  
  542.   } 
  543.  
  544.   /* pass to def dialog proc if needed */
  545.   if ( fPassToDef )
  546.     mresRtnVal = WinDefDlgProc( hwnd, usMsg, mp1, mp2 );
  547.   
  548.   return mresRtnVal;
  549. }
  550.  
  551. /* */
  552.  
  553. /*
  554.  * AboutDlgProc( hwndDlg, usMsg, mp1, mp2 ) : MRESULT;
  555.  *
  556.  *    hwndDlg        handle to dialog box
  557.  *    usMsg          message number
  558.  *    mp1            message parameter 1
  559.  *    mp2            message parameter 2
  560.  *
  561.  * This is the dialog procedure for the About dialog box.
  562.  *
  563.  */
  564.  
  565. MRESULT EXPENTRY AboutDlgProc( HWND hwndDlg, USHORT usMsg, MPARAM mp1, MPARAM mp2 )
  566. {
  567.   MRESULT       mresRtnVal;                 /* function return value  */
  568.   BOOL          fPassToDef;                 /* pass to def dlg proc?  */
  569.  
  570.   mresRtnVal = FALSE;
  571.   fPassToDef = FALSE;
  572.  
  573.   switch ( usMsg ) {
  574.  
  575.     case WM_INITDLG:
  576.       CenterPopup( hwndDlg, HWNDOWNER( hwndDlg ) );
  577.       break;
  578.  
  579.     case WM_COMMAND:
  580.       switch ( COMMANDMSG( &usMsg )->cmd ) {
  581.         case DID_OK:
  582.           WinDismissDlg( hwndDlg, TRUE );
  583.           break;
  584.         default:
  585.           fPassToDef = TRUE;
  586.           break;
  587.       }
  588.       break;
  589.  
  590.     default:
  591.       fPassToDef = TRUE;
  592.       break;
  593.  
  594.   }
  595.  
  596.   if ( fPassToDef )
  597.     mresRtnVal = WinDefDlgProc( hwndDlg, usMsg, mp1, mp2 );
  598.  
  599.   return mresRtnVal;
  600. }
  601.  
  602. /* */
  603.  
  604. /*
  605.  * Directory( szFileSpec, fsAttributes, hwndListBox ) : BOOL;
  606.  *
  607.  *    szFileSpec     file search specification
  608.  *    fsAttributes   file attributes to search for
  609.  *    hwndListBox    handle to listbox for directory
  610.  *
  611.  * This function searches the disk for files of the specified type
  612.  * and appends the results found to the list box whose handle is
  613.  * provided.  An error is generated and the process aborted if
  614.  * insufficient memory is available for the search.
  615.  *
  616.  * A value of TRUE is returned if the directory operation was
  617.  * successful.
  618.  *
  619.  */
  620.  
  621. static BOOL Directory(
  622.   NPSZ        szFileSpec,
  623.   USHORT      fsAttributes,
  624.   HWND        hwndListBox )
  625. {
  626.   BOOL        fContinue;              /* boolean search flag          */
  627.   BOOL        fDirOutput;             /* boolean directory flag       */
  628.   USHORT      iChar;                  /* index into char string       */
  629.   CHAR        szPath[64];             /* path specification string    */
  630.   CHAR        szSpec[64];             /* search specification string  */
  631.   HDIR        hdirSearch;             /* handle to search directory   */
  632.   USHORT      usSearchCount;          /* # of files to search for     */
  633.   FILEFINDBUF findbuf;                /* search result buffer         */
  634.   CHAR        szDate[16];             /* date string                  */
  635.   CHAR        szTime[16];             /* time string                  */
  636.   CHAR        szEntry[64];            /* current file name            */
  637.   SHORT       sErr;                   /* error code                   */
  638.  
  639.   /* initialization */
  640.   fContinue = TRUE;
  641.   fDirOutput = FALSE;
  642.  
  643.   /* separate file spec into path and wildcards */
  644.   for ( iChar=strlen(szFileSpec)-1; szFileSpec[iChar]!='\\'; iChar-- );
  645.   strcpy( szPath, szFileSpec );
  646.   szPath[iChar] = '\0';
  647.   strcpy( szSpec, &szFileSpec[iChar+1] );
  648.     
  649.   /* perform search for normal files */
  650.   hdirSearch = HDIR_CREATE;
  651.   usSearchCount = 1;
  652.   sErr = DosFindFirst(
  653.     szFileSpec,
  654.     &hdirSearch,
  655.     fsAttributes,
  656.     &findbuf,
  657.     sizeof(findbuf),
  658.     &usSearchCount,
  659.     0L
  660.   );
  661.   if ( !sErr ) {
  662.   
  663.     /* repeat until all entries exhausted */
  664.     do {
  665.     
  666.       /* output current directory if not done */
  667.       if ( !fDirOutput ) {
  668.         fDirOutput = TRUE;
  669.         sErr = SHORT1FROMMR( WinSendMsg(
  670.           hwndListBox,
  671.           LM_INSERTITEM,
  672.           MPFROMSHORT( LIT_END ),
  673.           szPath
  674.         ) );
  675.         switch ( sErr ) {
  676.  
  677.           case LIT_MEMERROR:
  678.             WinMessageBox(
  679.               HWND_DESKTOP,
  680.               WinQueryWindow( hwndListBox, QW_PARENT, FALSE ),
  681.               "Insufficient Memory!",
  682.               "File Finder",
  683.               0,
  684.               MB_OK | MB_ICONHAND
  685.             );
  686.             fContinue = FALSE;
  687.             break;
  688.  
  689.           case LIT_ERROR:
  690.             WinMessageBox(
  691.               HWND_DESKTOP,
  692.               WinQueryWindow( hwndListBox, QW_PARENT, FALSE ),
  693.               "Unable to Add Item to List Box!",
  694.               "File Finder",
  695.               0,
  696.               MB_OK | MB_ICONHAND
  697.             );
  698.             fContinue = FALSE;
  699.             break;
  700.  
  701.           default:
  702.             break;
  703.  
  704.         }
  705.       }  
  706.  
  707.       if ( fContinue ) {
  708.  
  709.         /* output current file name */
  710.         MakeDateString( findbuf.fdateLastWrite, szDate );
  711.         MakeTimeString( findbuf.ftimeLastWrite, szTime );
  712.         sprintf(
  713.           szEntry, 
  714.           "  %-12s %7ld %s %s",
  715.           findbuf.achName,
  716.           findbuf.cbFile,
  717.           szDate,
  718.           szTime
  719.         );
  720.           
  721.         /* add entry to file list box */
  722.         sErr = SHORT1FROMMR( WinSendMsg(
  723.           hwndListBox,
  724.           LM_INSERTITEM,
  725.           MPFROMSHORT( LIT_END ),
  726.           szEntry
  727.         ) );
  728.         switch ( sErr ) {
  729.  
  730.           case LIT_MEMERROR:
  731.             WinMessageBox(
  732.               HWND_DESKTOP,
  733.               WinQueryWindow( hwndListBox, QW_PARENT, FALSE ),
  734.               "Insufficient Memory!",
  735.               "File Finder",
  736.               0,
  737.               MB_OK | MB_ICONHAND
  738.             );
  739.             fContinue = FALSE;
  740.             break;
  741.  
  742.           case LIT_ERROR:
  743.             WinMessageBox(
  744.               HWND_DESKTOP,
  745.               WinQueryWindow( hwndListBox, QW_PARENT, FALSE ),
  746.               "Unable to Add Item to List Box!",
  747.               "File Finder",
  748.               0,
  749.               MB_OK | MB_ICONHAND
  750.             );
  751.             fContinue = FALSE;
  752.             break;
  753.  
  754.           default:
  755.             break;
  756.  
  757.         }
  758.  
  759.       }
  760.  
  761.       /* get next entry */
  762.       if ( fContinue )
  763.         sErr = DosFindNext(
  764.           hdirSearch,
  765.           &findbuf,
  766.           sizeof(findbuf),
  767.           &usSearchCount
  768.         );
  769.       
  770.     } while ( fContinue && !sErr );
  771.     
  772.   } 
  773.   
  774.   if ( fContinue ) {
  775.  
  776.     /* perform search for sub-directories */
  777.     sprintf( szEntry, "%s\\*.*", szPath );
  778.     hdirSearch = HDIR_CREATE;
  779.     usSearchCount = 1;
  780.     sErr = DosFindFirst(
  781.       szEntry,
  782.       &hdirSearch,
  783.       FILE_DIRECTORY,
  784.       &findbuf,
  785.       sizeof(findbuf),
  786.       &usSearchCount,
  787.       0L
  788.     );
  789.     if ( !sErr ) {
  790.   
  791.       /* repeat until all entries exhausted */
  792.       do {
  793.     
  794.         /* eliminate special directory entries */
  795.         if ( findbuf.attrFile == FILE_DIRECTORY
  796.         && findbuf.achName[0] != '.' ) {
  797.           sprintf(
  798.             szEntry,
  799.             "%s\\%s\\%s",
  800.             szPath,
  801.             findbuf.achName,
  802.             szSpec
  803.           );
  804.           fContinue = Directory( szEntry, fsAttributes, hwndListBox );
  805.         }
  806.       
  807.         /* get next entry */
  808.         if ( fContinue )
  809.           sErr = DosFindNext(
  810.             hdirSearch,
  811.             &findbuf,
  812.             sizeof(findbuf),
  813.             &usSearchCount
  814.           );
  815.  
  816.       } while ( fContinue && !sErr );
  817.     
  818.     }   
  819.  
  820.   }
  821.   
  822.   /* return final result */
  823.   return fContinue;
  824. }
  825.  
  826. /* */
  827.  
  828. /*
  829.  * CenterPopup( hwndPopup, hwndCenter ) : VOID;
  830.  *
  831.  *    hwndPopup      handle to popup window to center
  832.  *    hwndCenter     handle to window within which to center
  833.  *
  834.  * This function centers the popup window within the given window.
  835.  * To center within the entire desktop, pass HWND_DESKTOP as the
  836.  * hwndCenter parameter.  If the centered popup would be partially
  837.  * or completely off the edges of the screen, it is moved to be
  838.  * within the borders of the screen.
  839.  *
  840.  */
  841.  
  842. static VOID CenterPopup(
  843.   HWND        hwndPopup,
  844.   HWND        hwndCenter )
  845. {
  846.   LONG        cxPopup;                            /* popup width      */
  847.   LONG        cyPopup;                            /* popup height     */
  848.   LONG        cxCenter;                           /* parent width     */
  849.   LONG        cyCenter;                           /* parent height    */
  850.   LONG        cxScreen;                           /* screen width     */
  851.   LONG        cyScreen;                           /* screen height    */
  852.   RECTL       rclCenter;                          /* parent rectangle */
  853.   RECTL       rclPopup;                           /* popup rectangle  */
  854.  
  855.   /* get window rects for popup and center */
  856.   if ( !hwndCenter || (hwndCenter == HWND_DESKTOP) ) {
  857.     rclCenter.xLeft = 0;
  858.     rclCenter.yBottom = 0;
  859.     rclCenter.xRight = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  860.     rclCenter.yTop = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  861.   } else
  862.     WinQueryWindowRect( hwndCenter, &rclCenter );
  863.   WinQueryWindowRect( hwndPopup, &rclPopup );
  864.  
  865.   /* convert to screen coordinates */
  866.   MAPWINDOWRECTS( hwndPopup, HWND_DESKTOP, &rclPopup, 1 );
  867.   MAPWINDOWRECTS( hwndCenter, HWND_DESKTOP, &rclCenter, 1 );
  868.  
  869.   /* calculate window widths */
  870.   cxPopup = ABS(rclPopup.xRight - rclPopup.xLeft);
  871.   cyPopup = ABS(rclPopup.yTop - rclPopup.yBottom);
  872.   cxCenter = ABS(rclCenter.xRight - rclCenter.xLeft);
  873.   cyCenter = ABS(rclCenter.yTop - rclCenter.yBottom);
  874.  
  875.   /* center popup within parent */
  876.   rclPopup.xLeft = rclCenter.xLeft + (cxCenter-cxPopup)/2;
  877.   rclPopup.yBottom = rclCenter.yBottom + (cyCenter-cyPopup)/2;
  878.  
  879.   /* adjust position if hanging off on right or left */
  880.   cxScreen = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  881.   if ( rclPopup.xLeft+cxPopup >= cxScreen )
  882.     rclPopup.xLeft = (cxScreen - 1) - cxPopup;
  883.   if ( rclPopup.xLeft < 0 )
  884.     rclPopup.xLeft = 0;
  885.  
  886.   /* adjust position if hanging off on top or bottom */
  887.   cyScreen = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  888.   if ( rclPopup.yBottom+cyPopup >= cyScreen )
  889.     rclPopup.yBottom = (cyScreen - 1) - cyPopup;
  890.   if ( rclPopup.yBottom < 0 )
  891.     rclPopup.yBottom = 0;
  892.  
  893.   /* convert to parent coordinates */
  894.   rclPopup.xRight = rclPopup.yTop = 0;  /* don't care about topright */
  895.   MAPWINDOWRECTS( HWND_DESKTOP, HWNDPARENT( hwndPopup ), &rclPopup, 1 );
  896.  
  897.   /* place popup window using parent coordinates */
  898.   WinSetWindowPos(
  899.     hwndPopup,
  900.     NULL,
  901.     LOUSHORT( rclPopup.xLeft ),
  902.     LOUSHORT( rclPopup.yBottom ),
  903.     0,
  904.     0,
  905.     SWP_MOVE
  906.   );
  907. }
  908.  
  909. /* */
  910.  
  911. /*
  912.  * MakeDateString( fdate, szDate ) : VOID;
  913.  *
  914.  *    fdate          date to format
  915.  *    szDateTime     date string buffer
  916.  *
  917.  * This function formats a given date into a string form,
  918.  * taking into account the current user preference settings.
  919.  *
  920.  */
  921.  
  922. static VOID MakeDateString(
  923.   FDATE       fdate,
  924.   NPSZ        szDate )
  925. {
  926.   COUNTRYCODE ctryc;                  /* country code struct          */
  927.   COUNTRYINFO ctryi;                  /* country info for date        */
  928.   USHORT      cbCtryInfo;             /* # of bytes returned in ctryi */
  929.  
  930.   /* get country-specific info */
  931.   ctryc.country = 0;
  932.   ctryc.codepage = 0;
  933.   DosGetCtryInfo( sizeof(ctryi), &ctryc, &ctryi, &cbCtryInfo );
  934.   
  935.   /* format date accordingly */
  936.   sprintf(
  937.     szDate,
  938.     "%2u%s%02u%s%02u",
  939.     ctryi.fsDateFmt == DATEFMT_MM_DD_YY
  940.       ? fdate.month
  941.       : ctryi.fsDateFmt == DATEFMT_DD_MM_YY ? fdate.day : fdate.year+80,
  942.     ctryi.szDateSeparator,
  943.     ctryi.fsDateFmt == DATEFMT_MM_DD_YY ? fdate.day : fdate.month,
  944.     ctryi.szDateSeparator,
  945.     ctryi.fsDateFmt == DATEFMT_YY_MM_DD ? fdate.day : fdate.year+80
  946.   );
  947. }
  948.  
  949. /* */
  950.  
  951. /*
  952.  * MakeTimeString( ftime, szTime ) : VOID;
  953.  *
  954.  *    ftime          time to format
  955.  *    szTimeTime     time string buffer
  956.  *
  957.  * This function formats a given time into a string form,
  958.  * taking into account the current user preference settings.
  959.  *
  960.  */
  961.  
  962. static VOID MakeTimeString(
  963.   FTIME       ftime,
  964.   NPSZ        szTime )
  965. {
  966.   COUNTRYCODE ctryc;                  /* country code struct          */
  967.   COUNTRYINFO ctryi;                  /* country info for time        */
  968.   USHORT      cbCtryInfo;             /* # of bytes returned in ctryi */
  969.  
  970.   /* get country-specific info */
  971.   ctryc.country = 0;
  972.   ctryc.codepage = 0;
  973.   DosGetCtryInfo( sizeof(ctryi), &ctryc, &ctryi, &cbCtryInfo );
  974.   
  975.   /* format time accordingly */
  976.   if ( ctryi.fsTimeFmt )
  977.     sprintf(
  978.       szTime,
  979.       "%02u%s%02u",
  980.       ftime.hours,
  981.       ctryi.szTimeSeparator,
  982.       ftime.minutes
  983.     );
  984.   else
  985.     sprintf(
  986.       szTime,
  987.       "%2u%s%02u%c",
  988.       ftime.hours > 12
  989.         ? ftime.hours-12
  990.         : ftime.hours ? ftime.hours : 12,
  991.       ctryi.szTimeSeparator,
  992.       ftime.minutes,
  993.       ftime.hours < 12 ? 'a' : 'p'
  994.     );
  995. }
  996.