home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / infidx13.zip / infidx.c next >
Text File  |  1993-07-03  |  30KB  |  760 lines

  1. /*===========================================================================
  2.  * INFIDX
  3.  *
  4.  * -----ABSTRACT-------------------------------------------------------------
  5.  * A program to open an INF-file from a user configurable selection-listbox
  6.  * of all INF-files.
  7.  *
  8.  * -----PURPOSE--------------------------------------------------------------
  9.  * As I have much of my INF-files on a removable MO-disk, I don't
  10.  * want to create static WPS-objects for them, but I need a way to
  11.  * decect dynamically which INF-files are there and display only these ones.
  12.  * (Is the disk insertet or not?)
  13.  *
  14.  * Other advanteges are:
  15.  *  - fixed screen portion needed (independent of number of INF-files)
  16.  *  - order/sorting determined by user (order of dirs in BOOKSHELF and order
  17.  *    of entries in the config files)
  18.  *  - the setup is easily ported over all reinstallations, as it is done in
  19.  *    plain text files
  20.  *  - you can add your own (longer) titles to the INF-files in the list
  21.  *
  22.  * This program is to fullfill this job. It will search in all directories
  23.  * listed in the environment variable BOOKSHELF for a file called 'infidx'.
  24.  * These configuration files must hold the name and a description for all
  25.  * the INF-files that are to be shown in the selection list. There may reside
  26.  * one 'infidx'-file in each scanned directory and the contents of all of them
  27.  * is shown in the list in the order the entries are read.
  28.  *
  29.  * -----INSTALLATION---------------------------------------------------------
  30.  * This is a standalone program (no entries in INI-files no DLL). All you need
  31.  * is the EXE (in your PATH) and the following setup:
  32.  *  - Add all the directories containing your INF-files to the environment
  33.  *    variable BOOKSHELF.
  34.  *    NOTE: - Order matters. The directories are scanned in this order and by
  35.  *            this the directory of the INF-files you need most often should
  36.  *            come first.
  37.  *          - It is save to name not (allways) available drives/directories
  38.  *            like A:.
  39.  *  - Create a configuration file in all directories named in BOOKSHELF.
  40.  *    (see "infidx-FILE_FORMAT")
  41.  *    NOTE: -- Not all directories MUST have a config file.
  42.  *          -- It is possible to have absolute pathes in the config files and
  43.  *             let them refere to INF-files not in the directory of the
  44.  *             config-file, but this is NOT recommended. By this you would
  45.  *             have spread the information where your INF-files are located
  46.  *             and a movement of the files would make it neccessary to edit
  47.  *             the config-files too and not just adjust BOOKSHELF.
  48.  *  - Positioning of the list on screen.
  49.  *    The dialog with the list will startup at a fixed position. This position
  50.  *    defaults to the lower left corner of the screen (coordinates 0,0).
  51.  *    You can change the position in two ways:
  52.  *    - Set an environment variable by     "set INFIDX=yourx,youry"
  53.  *    - Invoke the program with arguments  "infidx yourx youry"
  54.  *
  55.  * -----INVOCATION-----------------------------------------------------------
  56.  * Start the program by:
  57.  *      infidx [yourx youry]
  58.  * (See INSTALLATION about the parameters.)
  59.  *
  60.  * -----USING----------------------------------------------------------------
  61.  * The program interfaces the user with a dialog. This dialog contains a
  62.  * listbox, and four buttons (OPEN, EXIT, REINIT and ABOUT).
  63.  *
  64.  * To view an INF-file, select the corresponding entry in the listbox and push
  65.  * the OPEN button.
  66.  *
  67.  * To exit the program just push the EXIT button.
  68.  *
  69.  * To rebuild the list after any changes made by you (changes of a config file
  70.  * or media changes in drives in your BOOKSHELF-path).
  71.  *
  72.  * -----infidx-FILE_FORMAT---------------------------------------------------
  73.  * These files can hold entry- and comment-lines. A comment-line starts with
  74.  * a '#' in the first column. All other lines are interpreted as entry-lines.
  75.  * An entry-line must hold at least two 'words'. The first word ist the param
  76.  * given to view (the name of the INF-file. All other words are the title that
  77.  * will be displayed in the list.
  78.  *
  79.  * Entry-lines are processed in the following way:
  80.  *  - remove trailing white-space
  81.  *  - skip leading white-space
  82.  *  - store the first sequence of non-white-space-characters as the argument
  83.  *    that will be passed to VIEW.EXE if this entry is selected
  84.  *    (You must not include the path of an INF-file, if it resides in the
  85.  *     same directory as the 'infidx'-file just processed, as a change dir to
  86.  *     this place will take place on the start of this entry.)
  87.  *  - skip the white-space following this first 'word'
  88.  *  - store the rest of the line as the entry-text to be shown in the list
  89.  *
  90.  * Sample-entry-lines
  91.  *   GG243730.INF                  Redbook 1 Control Program (general info)
  92.  *   GG243730.INF+GG243731.INF     Redbook 1 & 2
  93.  *   G:\BOOK.ADD\GG243730.INF      Redbook 1 Control Program (general info)
  94.  *
  95.  * -----LIMITS---------------------------------------------------------------
  96.  * The program can only handle 300 entries at all. To increase this value
  97.  * change the define in the header and recompile.
  98.  *
  99.  * -----IMPLEMENTATION-------------------------------------------------------
  100.  * This is a one day program and this shows the source. Do not blame me for the
  101.  * layout, grouping and endless functions. I wanted this program and I wanted
  102.  * to build it with C++ and a the IBM GUI-class-lib. But hello-world was over
  103.  * 500K in size after the half of this day. So I had to switch back to C-mode
  104.  * and hand made PM-calls on the run. (I hope XVT will lead to smaller EXE's
  105.  * in the future.)
  106.  *
  107.  * The program is made of a window and a dialog.
  108.  * The window does no user interaction, but is resposible for:
  109.  * - scanning the config-files
  110.  * - starting the view processes (via system("start /N view param"))
  111.  * - starting the dialog
  112.  * The dialog does all the user interaction.
  113.  *
  114.  * The building environment:
  115.  * - OS/2 2.1 GA (de)
  116.  * - IBM C/C++ Set/2 (beta B4)
  117.  * - TOOLKIT-20
  118.  * - LINK386 (version 2.01.005,  16.3.93)
  119.  * - NMAKE   (version 2.001.000, 11.2.93)
  120.  *
  121.  * -----LICENCE--------------------------------------------------------------
  122.  * This program may be used for free. You may distribute the WHOLE packet
  123.  * UNMODIFIED for any NONCOMERCIAL purpose.
  124.  * The source code is primaly supplied to allow recompilations for other
  125.  * OS/2 versions (if it is necessary at all). It although makes bugfixes and 
  126.  * enhancements possible. If you do something of the later please send the
  127.  * CHANGES TO ME, so that I can merge them in and release them. I would not
  128.  * like you to make any changes and distribute the program under the same
  129.  * name. You may use the code as a base for own developments but it would
  130.  * be nice to MENTION MY NAME.
  131.  *
  132.  * Just use it!
  133.  *
  134.  * -----DISCLAIMER-----------------------------------------------------------
  135.  * THIS PROGRAM DOES NOT FULLFILL ANY TASK AT ALL. THE ONLY GUARANTEE GIVEN
  136.  * IS, THAT THE PROGRAM WILL DAMAGE AND DESTROY THE HARDWARE AND SOFTWARE IT
  137.  * IS RUN ON. THE AUTHOR (THATS ME) IS NOT LIABLE FOR ANY LOSS YOU GET AS THE
  138.  * RESULT OF USING THIS PROGRAM.
  139.  *
  140.  * -----HISTORY--------------------------------------------------------------
  141.  * $Log:    infidx.c $
  142.  *Revision 1.4  93/07/03  18:41:43  UWE
  143.  *- seperated the program version number from the RCS revision
  144.  *- added a licence and disclaimer to the documentation
  145.  *
  146.  *Revision 1.3  93/07/03  09:33:21  UWE
  147.  *Fixed memory leak.
  148.  *On REINIT the allocated memory for the list elements was not free()'ed.
  149.  *initSelTable() & exitSelTable()  splitted:
  150.  *initSelTable(): only set all pointers to NULL (called once in main
  151.  *freeSelTable(): free all not NULL pointers in list (former exitSelTable()
  152.  *                called at first in fillSelTable() and on exit
  153.  *fillSelTable(): free any allocated memory and build list new with alloc()
  154.  *-
  155.  *Now compiled with IBM C++ GA version and Toolkit 2.1.
  156.  *
  157.  *Revision 1.2  93/07/02  11:09:52  UWE
  158.  *Added positioning possibility by user and REINIT-button.
  159.  *
  160.  *Revision 1.1  93/07/01  22:08:20  UWE
  161.  *Initial revision
  162.  *
  163.  * 
  164.  *===========================================================================*/
  165.  
  166. static char *rcsid = "$Revision: 1.4 $ $Date: 93/07/03 18:41:43 $";
  167.  
  168. /*
  169.  * C-library-declarations
  170.  */
  171. #include <ctype.h>
  172. #include <stdio.h>
  173. #include <stdlib.h>
  174. #include <string.h>
  175. #include <direct.h>
  176.  
  177. /*
  178.  * OS/2 system declarations
  179.  */
  180. #define INCL_BASE
  181. #define INCL_PM
  182. #include <os2.h>
  183.  
  184. /*
  185.  * program declarations (only defines used by compiler and resource compiler)
  186.  */
  187. #include "infidx.h"
  188.  
  189. static char szAreaClientClass[]  = "infidx-area";    /* window class names */
  190.  
  191. static int startupdrive = 3;
  192.  
  193.  
  194. /*==============================================================*/
  195. /* ERROR-display message box                                    */
  196. /*==============================================================*/
  197. void errmsgbox( HWND hwnd,   /* hwnd of calling window */
  198.                 char *txt1,  /* these texts are displayed */
  199.                 char *txt2 ) {
  200.   static char errmsg[500];
  201.   (void)strcpy ( errmsg, "ERROR\n" );
  202.   (void)strncat( errmsg, txt1, sizeof(errmsg) - strlen(errmsg) - 5 );
  203.   (void)strcat ( errmsg, "\n" );
  204.   (void)strncat( errmsg, txt2, sizeof(errmsg) - strlen(errmsg) - 5 );
  205.   (void)WinMessageBox( HWND_DESKTOP,
  206.                      hwnd,
  207.                      errmsg,
  208.                      PROGNAME,
  209.                      0,                           /* ID does not matter */
  210.                      MB_OK         | MB_ICONEXCLAMATION |
  211.                      MB_DEFBUTTON1 | MB_MOVEABLE      );
  212.   return;
  213. }
  214.  
  215. /*============================================================*/
  216. /* Window-procedure for the selection-dialog                  */
  217. /*                                                            */
  218. /* THIS FUNCTION AND THE CORESPONDING TYPES AND VARIABLES ARE */
  219. /* USED BY seldialog(). THEY MUST NOT BE USED FROM ELSEWHERE  */
  220. /*                                                            */
  221. /* The dialog is made of a listbox and an buttons.            */
  222. /*                                                            */
  223. /* The list box handling is down by the default procedures.   */
  224. /* All we have to do is to                                    */
  225. /* - fill the list box on creation,                           */
  226. /* - wait for a button to be pressed,                         */
  227. /* - detect which button it was                               */
  228. /* - query whether and which listentry was selected           */
  229. /* - map the listentry to a index                             */
  230. /* - return the user selection                                */
  231. /*                                                            */
  232. /* Return:                                                    */
  233. /*   UK_CANCEL      = no entry selected ( CANCEL )            */
  234. /*   else           = index of the selected entry             */
  235. /*============================================================*/
  236.  
  237. typedef struct {
  238.   int   index;
  239.   int   drive;
  240.   char  *param;
  241.   char  *wdir;
  242.   char  *text;
  243. } _UK_SEL_TABLE;
  244.  
  245. static _UK_SEL_TABLE _uk_sel_table[UK_MAX_ENTRIES];
  246.  
  247. /***********************************************************************/
  248. static void initSelTable( void )
  249. {
  250.   int  i;
  251.  
  252.   /*
  253.    * init to defined state for later free without thinking
  254.    */
  255.   for (i=0; i<UK_MAX_ENTRIES; i++)
  256.     {
  257.       _uk_sel_table[i].index = (ULONG)i;
  258.       _uk_sel_table[i].param = (char *)NULL;
  259.       _uk_sel_table[i].wdir  = (char *)NULL;
  260.       _uk_sel_table[i].text  = (char *)NULL;
  261.     }
  262.   return;
  263. }
  264.  
  265. /***********************************************************************/
  266. static void freeSelTable(void) {
  267.   int i;
  268.  
  269.   /*
  270.    * free all allocated memory
  271.    */
  272.   for (i=0; i<UK_MAX_ENTRIES; i++)
  273.     {
  274.       if (_uk_sel_table[i].param != (char *)NULL) (void)free(_uk_sel_table[i].param);
  275.       if (_uk_sel_table[i].wdir  != (char *)NULL) (void)free(_uk_sel_table[i].wdir );
  276.       if (_uk_sel_table[i].text  != (char *)NULL) (void)free(_uk_sel_table[i].text );
  277.     }
  278. }
  279.  
  280.  
  281. /***********************************************************************/
  282. static UK_RET fillSelTable( HWND hwnd )  /* only needed for errmsgbox() */
  283. {
  284.   int  i, len, index;
  285.   char *envpath, *parsep, *cwd, *cp1, *cp2;
  286.   char actpath[_MAX_PATH * 3];
  287.   char conffile[_MAX_PATH * 3];
  288.   FILE *conf;
  289.   char line[1000];
  290.  
  291.   /*
  292.    * free any allocated mem first
  293.    */
  294.   freeSelTable();
  295.  
  296.   /*
  297.    * get path from environment
  298.    */
  299.   if ( (envpath = getenv( ENVVARNAME )) == (char *)NULL )
  300.     {
  301.       errmsgbox( hwnd, "Environment variable not set.", ENVVARNAME );
  302.       return UK_ERR;
  303.     }
  304.  
  305.   /*
  306.    * loop over all entries in envpath
  307.    */
  308.   index = 0; /* let index be the next index to fill, that is one less as entries in list */
  309.   for (parsep=envpath; (index < UK_MAX_ENTRIES) && ((*parsep) != '\0') ; /* do nothing */ )
  310.     {
  311.       /*
  312.        * copy next entry from envpath to actpath
  313.        */
  314.       for ( i=0;
  315.                (i < _MAX_PATH)
  316.             && (*parsep != '\0')
  317.             && (*parsep != ';');
  318.             i++, parsep++ )
  319.           actpath[i] = *parsep;
  320.       actpath[i] = '\0';
  321.       if ( *parsep == ';' )
  322.           parsep++;
  323.       /* make actpath a full path with drive */
  324.       if ( actpath[1] != ':' )
  325.         { /* no drive; shift path by 2 and insert drive */
  326.           for (i=strlen(actpath); i>=0; i--)
  327.               actpath[i+2] = actpath[i];
  328.           actpath[1] = ':';
  329.           actpath[0] = _getdrive() - 1 + 'A';
  330.         } /* no drive */
  331.       if ( actpath[2] != '\\' )
  332.         { /* relative path */
  333.           if ( (cwd = _getcwd((char *)NULL, _MAX_PATH)) != (char *)NULL )
  334.             {
  335.               len = strlen(cwd);
  336.               if ( cwd[len-1] == '\\' )
  337.                   len--;
  338.               /* shift relative path by length of cwd incl. \\ */
  339.               for (i=strlen(actpath); i>=2; i--)
  340.                   actpath[i+len] = actpath[i];
  341.               /* fill in the cwd */
  342.               for (i=0; i<len; i++)
  343.                   actpath[i+2] = cwd[i];
  344.               actpath[len+2] = '\\';
  345.               (void)free(cwd);
  346.             }
  347.         } /* relative path */
  348.       /* copy actpath to conffile */
  349.       (void)strcpy( conffile, actpath );
  350.       /* add trailing \\ if neccessary */
  351.       len = strlen(conffile);
  352.       if ( conffile[len-1] != '\\' )
  353.         {
  354.           conffile[len] = '\\';
  355.           len++;
  356.           conffile[len] = '\0';
  357.         }
  358.       /* add our config file name to actpath */
  359.       (void)strcat( conffile, CONFNAME );
  360.  
  361.       /*
  362.        * open config file (if any)
  363.        */
  364.       if ( (conf = fopen( conffile, "r")) != (FILE *)NULL )
  365.         { 
  366.           while (  (index < UK_MAX_ENTRIES)
  367.                 && (fgets( line, sizeof(line), conf) != (char *)NULL )
  368.                 )
  369.             {
  370.               /* strip trailing white space */
  371.               for ( cp1 = (strlen(line) == 0) ? line : (line + strlen(line) - 1);
  372.                     (cp1 >= line) && ( (*cp1 == ' ') || (*cp1 == '\t') || (*cp1 == '\n') );
  373.                     cp1-- )
  374.                   *cp1 = '\0';
  375.               /* position cp1 on first non white space */
  376.               for ( cp1 = line;
  377.                        (*cp1 != '\0')
  378.                     && ( (*cp1 == ' ') || (*cp1 == '\t') );
  379.                     cp1++ )
  380.                   ; /* do nothing in loop body */
  381.               /* search end of first word; end it by \0 and let cp2 point to rest of line */
  382.               for ( cp2 = cp1;
  383.                     (*cp2 != '\0') && (*cp2 != '\t') && (*cp2 != ' ');
  384.                     cp2++ )
  385.                   ; /* do nothing in loop body */
  386.               if (  ( *cp2 != '\0' ) /* implies *cp1 != '\0' */
  387.                  && ( *cp1 != '#'  )
  388.                  )
  389.                 {
  390.                   *cp2 = '\0';
  391.                   for ( cp2++;
  392.                            (*cp2 != '\0')
  393.                         && ( (*cp2 == ' ') || (*cp2 == '\t') );
  394.                         cp2++ )
  395.                       ; /* do nothing in loop body */
  396.                   if ( *cp2 != '\0' )
  397.                     { /* cp1 and cp2 are in position */
  398.                       /*
  399.                        * fill entry in table ******************
  400.                        */
  401.                       if ( (_uk_sel_table[index].param = (char *)malloc(strlen(cp1)+1))
  402.                          == (char *)NULL )
  403.                         {
  404.                           (void)fclose(conf);
  405.                           errmsgbox( hwnd, "Out of memory", "malloc()" );
  406.                           return UK_ERR;
  407.                         }
  408.                       (void)strcpy(_uk_sel_table[index].param, cp1);
  409.                       if ( (_uk_sel_table[index].wdir  = (char *)malloc(strlen(actpath)+1))
  410.                          == (char *)NULL )
  411.                         {
  412.                           (void)fclose(conf);
  413.                           errmsgbox( hwnd, "Out of memory", "malloc()" );
  414.                           return UK_ERR;
  415.                         }
  416.                       (void)strcpy(_uk_sel_table[index].wdir , actpath);
  417.                       if ( (_uk_sel_table[index].text  = (char *)malloc(strlen(cp2)+1))
  418.                          == (char *)NULL )
  419.                         {
  420.                           (void)fclose(conf);
  421.                           errmsgbox( hwnd, "Out of memory", "malloc()" );
  422.                           return UK_ERR;
  423.                         }
  424.                       (void)strcpy(_uk_sel_table[index].text , cp2);
  425.                       _uk_sel_table[index].drive = toupper(_uk_sel_table[index].wdir[0]) - 'A' + 1;
  426.                       index++;
  427.  
  428.                     } /* cp1 and cp2 are in position */
  429.                 } /* more than one word in line */
  430.             } /* loop over lines in file */
  431.           (void)fclose(conf);
  432.         } /* can open file */
  433.     } /* loop over entries in envpath */
  434.   
  435.   /*
  436.    * at least one entry in list ?
  437.    */
  438.   if ( index <= 0 )
  439.     {
  440.       errmsgbox( hwnd, "No config file (" CONFNAME ") found in direcories of",
  441.                         ENVVARNAME " or none holds a valid entry." );
  442.       return UK_ERR;
  443.     }
  444.  
  445.   /*
  446.    * all entries read or list full ?
  447.    */
  448.  
  449.   /*
  450.    * if we get to this point all went well
  451.    */
  452.   if ( index == UK_MAX_ENTRIES )
  453.     {
  454.       errmsgbox( hwnd, "Reached maximum number of allowed entries.",
  455.                        "(Proceeding with incomplete list.)" );
  456.     }
  457.   return UK_OK;
  458. }
  459.  
  460.  
  461. MRESULT EXPENTRY ukseldlg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  462. {
  463.   HWND  lboxhwnd;
  464.   LONG  index;
  465.   int   i;
  466.   char  aboutmsg[300];
  467.  
  468.   switch ( msg )
  469.     {
  470.     case WM_INITDLG:
  471.       lboxhwnd = WinWindowFromID( hwnd, UK_SEL_LBOX );
  472.       for ( i = 0;
  473.             (i < UK_MAX_ENTRIES) && (_uk_sel_table[i].param != (char *)NULL);
  474.             i++ )
  475.         {
  476.           (void)WinInsertLboxItem( lboxhwnd, 
  477.                                    LIT_END, 
  478.                                    (PSZ)(_uk_sel_table[i].text) );
  479.         }
  480.       return( (MRESULT)FALSE );
  481.  
  482.     case WM_COMMAND:
  483.       switch (LOUSHORT( mp1 ))  /* the ID of the window generating this cmd */
  484.         {
  485.         case UK_SEL_OPEN:         /* OPEN-push-button */
  486.           lboxhwnd = WinWindowFromID( hwnd, UK_SEL_LBOX );
  487.           index = WinQueryLboxSelectedItem( lboxhwnd );
  488.           if ( index != LIT_NONE )
  489.             {
  490.               (void)WinDismissDlg( hwnd, _uk_sel_table[ index ].index );
  491.               return( (MRESULT)0 );
  492.             }
  493.           /* show a little help */
  494.           (void)WinMessageBox( HWND_DESKTOP,
  495.                              hwnd,
  496.                              "You must select an entry and push OPEN to view\n"
  497.                              "an entry, push EXIT to end the program or\n"
  498.                              "push REINIT to rebuild the list.",
  499.                              PROGNAME,
  500.                              0,                           /* ID does not matter */
  501.                              MB_OK         | MB_ICONEXCLAMATION |
  502.                              MB_DEFBUTTON1 | MB_MOVEABLE      );
  503.           return( (MRESULT)0 );
  504.  
  505.         case UK_SEL_CANCEL:     /* CANCEL-push-button */
  506.           (void)WinDismissDlg( hwnd, UK_CANCEL );
  507.           return( (MRESULT)0 );
  508.  
  509.         case UK_SEL_REINIT:     /* REINIT-push-button */
  510.           (void)WinDismissDlg( hwnd, UK_REINIT );
  511.           return( (MRESULT)0 );
  512.  
  513.         case UK_SEL_ABOUT:      /* ABOUT-push-button */
  514.           /* show version string */
  515.           (void)sprintf(aboutmsg,
  516.                         "by Uwe Koenzen (email: uk@acs451.GEI-Aachen.de)\nVersion %s (internal: %s)",
  517.                         UKVERSION,
  518.                         rcsid );
  519.           (void)WinMessageBox( HWND_DESKTOP,
  520.                              hwnd,
  521.                              aboutmsg,
  522.                              PROGNAME,
  523.                              0, /* ID does not matter */
  524.                              MB_OK         | MB_ICONEXCLAMATION |
  525.                              MB_DEFBUTTON1 | MB_MOVEABLE      );
  526.           return ((MRESULT)0);
  527.  
  528.         }
  529.  
  530.     default:
  531.       return( (MRESULT)WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
  532.     }
  533. }
  534.  
  535. /*==============================================================*/
  536. /* This function brings up the selection dialog and returns     */
  537. /* the selected entry or UK_CANCEL, if no selection was made    */
  538. /* made by the user.                                            */
  539. /*                                                              */
  540. /* Parameter:                                                   */
  541. /*   myhandle = window-handle of the calling window             */
  542. /*              (only used as owner-window for the              */
  543. /*               dialog-window; parent is the desktop)          */
  544. /* Return:                                                      */
  545. /*   selected index or UK_CANCEL                                */
  546. /*==============================================================*/
  547.  
  548. int seldialog( HWND myhandle )
  549. {
  550.   LONG swapindex;
  551.   swapindex = WinDlgBox( HWND_DESKTOP, myhandle , /* cast from ULONG to LONG */
  552.                         ukseldlg, (HMODULE)NULL,
  553.                         UK_SEL_DLG, (PVOID)&swapindex );
  554.   switch ( swapindex )
  555.     {
  556.     case UK_CANCEL:
  557.       return( UK_CANCEL );
  558.     case UK_REINIT:
  559.       return( UK_REINIT );
  560.     default:
  561.       return( (int)swapindex );
  562.     }
  563. }
  564.  
  565. /*==============================================================*/
  566. /* Window-procedure for the windows of class szAreaClientClass. */
  567. /*                                                              */
  568. /* Beside the standard messages handled (CREATE,PAINT,SHOW; not */
  569. /* DESTROY,QUIT as no resources are allocated by this class),   */
  570. /* this procedure handles the private commands WMP_OPENSEL.     */
  571. /*==============================================================*/
  572.  
  573. static MRESULT EXPENTRY AreaClientWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  574. {
  575.   static char   cmd[1000] = "";
  576.   HPS    hps, hps_unused;
  577.   RECTL  rcl;
  578.   int    index;
  579.   
  580.   switch (msg)
  581.     {
  582.     case WM_CREATE:
  583.       (void)WinDefWindowProc( hwnd, msg, mp1, mp2 );
  584.       (void)WinPostMsg( hwnd, WMP_INITSEL, (MPARAM)0, (MPARAM)0 );
  585.       return( (MRESULT)FALSE );
  586.  
  587.     case WM_PAINT:
  588.       /* clear window by painting it in BACK_COLOR */
  589.       hps_unused = WinBeginPaint (hwnd, 0L, 0L); /* tell PM we will draw */
  590.       hps = WinGetPS( hwnd ); /* get presentation space for whole client area */
  591.       (void)WinQueryWindowRect (hwnd, &rcl); /* and query the rectangle
  592.                                               * coordinates
  593.                                               */
  594.       (void)WinFillRect(hps, &rcl, SYSCLR_BACKGROUND);
  595.       (void)WinEndPaint (hps);  /* flag end of update, so that this client
  596.                                  * window will be marked ok by PM
  597.                                  */
  598.       return (0);
  599.  
  600.     case WMP_INITSEL:
  601.       if (fillSelTable( hwnd ) == UK_OK)
  602.           (void)WinPostMsg( hwnd, WMP_OPENSEL, (MPARAM)0, (MPARAM)0 );
  603.       else
  604.           (void)WinSendMsg (hwnd, WM_CLOSE, 0L, 0L);
  605.       return (0);
  606.  
  607.     case WMP_OPENSEL:
  608.       if ((index = seldialog( hwnd )) == UK_CANCEL)
  609.         {
  610.           (void)WinSendMsg (hwnd, WM_CLOSE, 0L, 0L);
  611.           return (0);
  612.         }
  613.       if ( index == UK_REINIT )
  614.         {
  615.           (void)WinSendMsg (hwnd, WMP_INITSEL, 0L, 0L);
  616.           return (0);
  617.         }
  618.       /*
  619.        * a selection was made
  620.        */
  621.       /* build command to execute */
  622.       (void)sprintf(cmd, "start /N view %s", _uk_sel_table[index].param);
  623.       /* change to drive */
  624.       if ( _chdrive(_uk_sel_table[index].drive) < 0 )
  625.         {
  626.           cmd[0] = (char)(_uk_sel_table[index].drive - 1 + 'A');
  627.           cmd[1] = '\0';
  628.           errmsgbox( hwnd, "Can not change drive to", cmd );
  629.         }
  630.       else
  631.         {
  632.           /* change to directory */
  633.           if ( _chdir(_uk_sel_table[index].wdir) < 0 )
  634.               errmsgbox( hwnd, "Can not change directory to", _uk_sel_table[index].wdir );
  635.           else
  636.               /* now execute command */
  637.               (void)system(cmd);
  638.         }
  639.       (void)_chdrive(startupdrive);
  640.       (void)_chdir("\\");
  641.       /* reopen selection dialog */
  642.       (void)WinPostMsg( hwnd, WMP_OPENSEL, (MPARAM)0, (MPARAM)0 );
  643.       return (0);
  644.     } /* switch (msg) */
  645.   return (WinDefWindowProc (hwnd, msg, mp1, mp2));
  646. }
  647.  
  648. /*====================================================================*/
  649. /* Determine x- and y-position of area-window (and by this of dialog) */
  650. /* Order is:                                                          */
  651. /*   default-position                                                 */
  652. /*   from environment-variable  x,y                                   */
  653. /*   from arguments to program  x y                                   */
  654. /*====================================================================*/
  655. void getxypos(int argc, char *argv[], long *xpos, long *ypos) {
  656.     char *env,*komma;
  657.  
  658.     *xpos = (long)DEF_XPOS;
  659.     *ypos = (long)DEF_YPOS;
  660.  
  661.     if (  ( (env = getenv( POSENVVAR )) != (char *)NULL )
  662.        && (strlen(env) >= 3)
  663.        && ((komma = strchr(env,',')) != (char *)NULL)
  664.        && (komma != env)
  665.        && (isdigit(*env))
  666.        && (isdigit(*(komma+1)))
  667.        )
  668.       {
  669.         *xpos = (long)atoi(env);
  670.         *ypos = (long)atoi(komma+1);
  671.       }
  672.  
  673.     if (  (argc == 3)
  674.        && (isdigit(*(argv[1])))
  675.        && (isdigit(*(argv[2])))
  676.        )
  677.       {
  678.         *xpos = (long)atoi(argv[1]);
  679.         *ypos = (long)atoi(argv[2]);
  680.       }
  681.  
  682.    return;
  683. }
  684.  
  685. /*==============================================================*/
  686. /* main                                                         */
  687. /* - initialise PM and get HAB of application                   */
  688. /* - create message queue for application                       */
  689. /* - register the 3 client window classes                       */
  690. /* - create the 3 windows                                       */
  691. /* - fill the window words of the CtrlClientWindow              */
  692. /* - resize and position the Ctlr- and the Paint-window         */
  693. /* - get all messages for this application and dispatch it to   */
  694. /*   the appropriate window until a WM_QUIT is received         */
  695. /* - destroy all windows                                        */
  696. /* - destroy the message queue                                  */
  697. /* - release PM and exit                                        */
  698. /*==============================================================*/
  699.  
  700. int main (int argc, char *argv[])
  701. {
  702.   ULONG    flFrameFlags;
  703.   HAB      hab;
  704.   HMQ      hmq;
  705.   HWND     hwndAreaFrame;
  706.   HWND     hwndAreaClient;
  707.   QMSG     qmsg;
  708.   long     xpos, ypos;
  709.  
  710.   startupdrive = _getdrive();
  711.   initSelTable();  /* fill in area-window-proc */
  712.   getxypos(argc, argv, &xpos, &ypos);
  713.   
  714.   hab = WinInitialize ((ULONG)0) ;               /* only 0 allowed */
  715.   if (hab == NULLHANDLE)
  716.     {
  717.       return 2;
  718.     }
  719.  
  720.   hmq = WinCreateMsgQueue (hab, 0L) ;      /* 0 == default queue size */
  721.   if (hmq == NULLHANDLE)
  722.       (void)WinTerminate (hab);
  723.  
  724.  
  725.   
  726.   (void)WinRegisterClass (hab, szAreaClientClass, AreaClientWndProc,
  727.                           CS_SIZEREDRAW,
  728.                           0L);            /* 0 window words storage reserved */
  729.   
  730.   flFrameFlags = FCF_TITLEBAR | FCF_ICON | FCF_TASKLIST;
  731.   
  732.   hwndAreaFrame = WinCreateStdWindow (
  733.                                    HWND_DESKTOP,
  734.                                    WS_VISIBLE | WS_CLIPCHILDREN,
  735.                                    &flFrameFlags,
  736.                                    szAreaClientClass,
  737.                                    PROGNAME,
  738.                                    0L,
  739.                                    0,
  740.                                    ID_FW_AREA,
  741.                                    &hwndAreaClient) ;
  742.   
  743.   (void)WinSetWindowPos( hwndAreaFrame,
  744.                         HWND_TOP,
  745.                         xpos,ypos,        /* x,y-coord rel to parent */
  746.                         300L,20L,         /* x,y-dimension */
  747.                         SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE );
  748.  
  749.   while (WinGetMsg (hab, &qmsg, 0L, 0, 0))
  750.     (void)WinDispatchMsg (hab, &qmsg);
  751.   
  752.   freeSelTable();  /* fill in area-window-proc */
  753.   (void)WinDestroyWindow (hwndAreaClient);
  754.   (void)WinDestroyWindow (hwndAreaFrame);
  755.   (void)WinDestroyMsgQueue (hmq);
  756.   (void)WinTerminate (hab);
  757.   return (0);
  758. }
  759.  
  760.