home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PF.ZIP / PICKFILE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-12-20  |  18.3 KB  |  573 lines

  1.  
  2. /*
  3.  
  4. DEVELOPING A FILE SELECTION WINDOW IN TURBO C
  5. ----------------------------------------------
  6.        Garry J. Vass   [72307,3311]
  7.  
  8. Copyright (c), 1987, Telemacus Software Associates
  9.  
  10.  
  11. This file contains the nucleus routines for developing
  12. a file selection window using Turbo C and QLIB (release
  13. 4 or above).  File selection windows have the following
  14. advantages:
  15.  
  16.     -  As can be seen here, they are VERY easy to develop.
  17.  
  18.     -  The user is not burdened with having to remember
  19.        file names;
  20.  
  21.     -  The programmer has more control over the selection
  22.        and processing of files; and
  23.  
  24.     -  The overall presentation of the program is improved.
  25.  
  26. GENERAL NOTES, CAVEATS, AND DRUNKEN RAMBLINGS
  27. ---------------------------------------------
  28.  
  29. Use the LARGE memory model for compiling this program.
  30.  
  31. Where possible, I tried to use the keyboard conventions (arrows,
  32. home, end, etc) in the file selection routines found in NU.EXE
  33. (viz., Norton Utility).  The program does not have the feature
  34. of scrolling the entire screen display to accomodate an additional
  35. column.
  36.  
  37. This prototype stubs in the error processing if the maximum
  38. number of files has been exceeded.  These must be added
  39. according to the application.
  40.  
  41. An array structure is used to store and present the file names.
  42. Arrays are handy because the members can be easily accessed.  They
  43. are troublesome because they must be specified to an explicit size
  44. and must be contained within the data segment.  Production quality
  45. and/or heavy duty directory processing routines should use
  46. linked lists, or related dynamic structures, for storing file names.
  47.  
  48. This program was developed on an IBM AT with EGA under DOS 3.2 using
  49. Turbo C 1.0 and QLIB-4.  The functions (modified for linked list
  50. structures and extended error processing logic) were incorporated
  51. into a production-level expert system - with hooks into Turbo Prolog.
  52. The application itself deals with the optimal allocation/assignment
  53. and PSA good delivery rules of wirable MBS pools (a Wall Street
  54. investment banking application).  Thanks, Borland!!
  55.  
  56. As might be expected, OS/2 users must use the dos box for this
  57. program.  QLIB for OS/2 is currently in the works...
  58. */
  59.  
  60. /***********************  BEGIN SOURCE FOR PICKFILE  ********************/
  61. /***********************  INCLUDES FOR PICKFILE  ************************/
  62. /* dir.h contains the directory get and file name parse functions       */
  63. #include <dir.h>
  64. /* qtypes.c contains the requisite type declarations for this program   */
  65. #include <qtypes.c>
  66. /* qkeys.c contains the qreadkbd translation tokens (optional)          */
  67. #include <qkeys.c>       /*  can be found in go bor                     */
  68. /* qcolors.c contains the english tokens for screen attributes (optional)*/
  69. #include <qcolors.c>     /*  can be found in go bor                     */
  70. /***********************  END OF INCLUDES FOR PICKDIR  *******************/
  71.  
  72. /***********************  DEFINES FOR PICKFILE  **************************/
  73. #define filename       filefb.ff_name    /* abbreviation         */
  74. #define file_att       filefb.ff_attrib  /* abbreviation         */
  75. #define filesize       filefb.ff_fsize   /* abbreviation         */
  76. #define filedate       filefb.ff_fdate   /* abbreviation         */
  77. #define filetime       filefb.ff_ftime   /* abbreviation         */
  78. #define MAX_FILES       100    /* Max files before error logic   */
  79. #define WINDOW_UL_X     0      /* Box coordinates for PICKFILE   */
  80. #define WINDOW_UL_Y     0      /* window                         */
  81. #define WINDOW_LR_X     79     /*                                */
  82. #define WINDOW_LR_Y     22     /*                                */
  83. #define XINCREMENT      15     /* Horizontal increment           */
  84. #define FILE_BACK       black  /* File name display background   */
  85. #define FILE_FORE       white  /* File name display foreground   */
  86. #define WINDOW_DEPTH    WINDOW_LR_Y - WINDOW_UL_Y
  87. /************************  END OF DEFINES FOR PICKFILE  ******************/
  88. /************************  STRUCTS AND TYPEDEFS FOR PICKFILE  ************/
  89. struct   ffblk filefb;  /* see dir.h  */
  90. typedef  struct
  91.     {
  92.     qint sx;                  /* screen column for this file  */
  93.     qint sy;                  /* screen row for this file     */
  94.     struct ffblk file_info;   /* nested structure             */
  95.     }
  96.     full_file_record;
  97.  
  98. /******************** END OF STRUCTS AND TYPES FOR PICKFILE  ***************/
  99. /*******************  GLOBAL VARIABLES FOR PICKFILE  ***********************/
  100. full_file_record
  101.          ffr[MAX_FILES];   /*  Array for found files      */
  102. int      filesfound  = 0;  /*  Count for found files      */
  103. qint     currentsx   = 0;  /*  For screen save/restore    */
  104. qint     currentsy   = 0;  /*  For screen save/restore    */
  105. qint     maincounter = 0;  /*  General index              */
  106. qint     originalx   = 0;  /*  For screen save/restore    */
  107. qint     originaly   = 0;  /*  For screen save/restore    */
  108. qstring  mainstring  = ""; /*  For return value           */
  109.  
  110. prompt_record filespecification =
  111.     {
  112.     "PLEASE ENTER A DIRECTORY SEARCH SPECIFICATION:  ",/* tag qstring */
  113.     "*.exe",                         /* tag value */
  114.     0,                               /* tag x*/
  115.     12,                              /* tag y*/
  116.     50,                              /* val x */
  117.     12,                              /* val y */
  118.     13,                              /* max chars */
  119.     bright_white,                    /* tag fore */
  120.     black,                           /* tag back */
  121.     white,                           /* val fore */
  122.     dark_blue,                       /* val back */
  123.     0,                               /* case conversion */
  124.     " ",                             /* edit mask       */
  125.     " ", 0, " ", " ", " ", 0};
  126. /************************* END OF GLOBAL VARIABLES FOR PICKFILE ***********/
  127. /**************************************************************************/
  128. /************************* PICKFILE SUPPORT FUNCTIONS  ********************/
  129. void initialize_coordinates()
  130. {
  131. /*
  132. This function simply initializes the screen coordinates to where
  133. the display of file names should begin.
  134. */
  135. currentsx = WINDOW_UL_X + 2;
  136. currentsy = WINDOW_UL_Y + 1;
  137. }
  138. /*************************************************************************/
  139. void update_current_coordinates()
  140. {
  141. /*
  142. This service function increments the screen coordinates
  143. in a verticle manner.  As each column is filled, the next
  144. column is calculated using the XINCREMENT variable.
  145. */
  146. ++currentsy;
  147. if (currentsy >= WINDOW_LR_Y)
  148.     {
  149.     currentsy = WINDOW_UL_Y + 1;
  150.     currentsx = currentsx + XINCREMENT;
  151.     if (currentsx + XINCREMENT > WINDOW_LR_X)
  152.         {
  153.         printf("program limits exceeded\n");
  154.         /*  calls to error logic go here  */
  155.         abort();
  156.         }
  157.     }
  158. }
  159. /*************************************************************************/
  160. qint get_files
  161.     (
  162.     qstring search_specification
  163.     )
  164. {
  165. /*
  166. This function accepts a search specification (such as *.*) and loops
  167. through the current directory, storing each match into an array.
  168. */
  169. int filerc = 0;
  170. filesfound = 0;
  171. filerc = findfirst(search_specification, &filefb, 0xff);
  172. while (!filerc)
  173.     {
  174.     if ((filename[0] != 46)  &&     /*  exclude those pesky periods... */
  175.         (file_att    != 0x10))      /*  and subdirectories             */
  176.         {
  177.         ffr[filesfound].sx = currentsx;
  178.         ffr[filesfound].sy = currentsy;
  179.         ffr[filesfound].file_info = filefb;
  180.         update_current_coordinates();
  181.         ++filesfound;
  182.         }
  183.     if (filesfound >= MAX_FILES)
  184.         {
  185.         printf("program limits exceeded\n");
  186.         /*  calls to error logic go here  */
  187.         abort();
  188.         }
  189.     filerc = findnext(&filefb);
  190.     }
  191. return(filesfound - 1);
  192. }
  193. /*************************************************************************/
  194. void display_file_box()
  195. {
  196. /*
  197. This is the engine presentation routine.  It draws a box then
  198. displays all the matched file names at the screen coordinates.
  199. */
  200. qint displaycounter;
  201. qdrawbox
  202.    (WINDOW_UL_X,
  203.     WINDOW_UL_Y,
  204.     WINDOW_LR_X,
  205.     WINDOW_LR_Y,
  206.     "",
  207.     "[ PRESS F1 FOR HELP ]",
  208.     (dark_blue<<4) | white,
  209.     bright_white,
  210.     bright_white);
  211. for (displaycounter=0;displaycounter<=filesfound;++displaycounter)
  212.     {
  213.     qsnap
  214.         (ffr[displaycounter].file_info.ff_name,
  215.         ffr[displaycounter].sx,
  216.         ffr[displaycounter].sy,
  217.         bright_white);
  218.     }
  219. }
  220. /*************************************************************************/
  221. void unhighlight_area
  222.     (
  223.     qint  startx,
  224.     qint  starty,
  225.     qint  length
  226.     )
  227. {
  228. qreset_box_attribute
  229.     (startx,
  230.     starty,
  231.     startx + length,
  232.     starty,
  233.     (FILE_BACK<<4) | FILE_FORE);
  234. }
  235. /*************************************************************************/
  236. void highlight_area
  237.     (
  238.     qint  startx,
  239.     qint  starty,
  240.     qint  length
  241.     )
  242. {
  243. qreset_box_attribute
  244.     (startx,
  245.     starty,
  246.     startx + length,
  247.     starty,
  248.     (FILE_FORE<<4) | FILE_BACK);
  249. }
  250. /*************************************************************************/
  251. void give_file_help()
  252. {
  253. /*
  254. This function displays the help window when the F1 key is hit.
  255. */
  256. qscreen file_help_screen;
  257. qint    file_help_ul_x = 20;
  258. qint    file_help_ul_y = 5;
  259. qint    file_help_lr_x = 60;
  260. qint    file_help_lr_y = 15;
  261. qint    file_help_index;
  262. qstring file_help_text[9] =
  263.     {
  264.     "Use the arrow keys (Up, Down, Home,  ",
  265.     "and End, to orient the highlighted   ",
  266.     "area on the file you wish to select. ",
  267.     "Press the Enter (Return, Advance,    ",
  268.     "etc) key to exit with your selection.",
  269.     "                                     ",
  270.     "To exit without making a selection,  ",
  271.     "press the Escape key.                ",
  272.     "                                     "
  273.     };
  274. qwindow_save             /*  save the screen area */
  275.     (file_help_ul_x,
  276.      file_help_ul_y,
  277.      file_help_lr_x,
  278.      file_help_lr_y,
  279.      file_help_screen);
  280. qdrawbox                 /*  draw a box for the help window  */
  281.     (file_help_ul_x,
  282.      file_help_ul_y,
  283.      file_help_lr_x,
  284.      file_help_lr_y,
  285.      "",
  286.      "[ hit any key to continue ]",
  287.      bright_white,
  288.      bright_white,
  289.      bright_white | blink);
  290. for (file_help_index=0;file_help_index<9;++file_help_index)
  291.     {
  292.     qsnap                /*  display the help text  */
  293.         (file_help_text[file_help_index],
  294.          file_help_ul_x + 2,
  295.          file_help_ul_y + file_help_index + 1,
  296.          bright_white);
  297.     }
  298. file_help_index = qreadkbd();   /*  wait for a key  */
  299. qwindow_restore                 /*  restore the screen area  */
  300.     (file_help_ul_x,
  301.      file_help_ul_y,
  302.      file_help_lr_x,
  303.      file_help_lr_y,
  304.      file_help_screen);
  305. }
  306. /*************************************************************************/
  307. qint pick_file_menu()
  308. {
  309. /*
  310. This is the driver function for the PICKFILE presentation.  It is
  311. similar in form and structure to the qbounce(~~~) function (available
  312. at go bor).
  313. */
  314.  
  315. qint menucounter;
  316. qint keypressed;
  317. keypressed = 0;
  318. menucounter = 0;
  319. qgotoxy(0, 25);
  320. highlight_area                 /* highlight the first file  */
  321.     (ffr[menucounter].sx,
  322.      ffr[menucounter].sy,
  323.      XINCREMENT - 1);
  324. while (keypressed != return_pressed)
  325.     {
  326.     keypressed = qreadkbd();   /*  get a keystroke  */
  327.     if (keypressed != return_pressed)
  328.         {
  329.         unhighlight_area
  330.             (ffr[menucounter].sx,
  331.              ffr[menucounter].sy,
  332.              XINCREMENT - 1);
  333.         switch (keypressed)
  334.             {
  335.             case escape_pressed:
  336.                 {  /* escape means exit with no file selection */
  337.                 return (filesfound + 1);
  338.                 }
  339.             case f01pressed:
  340.                 {  /* F1 means give help  */
  341.                 give_file_help();
  342.                 break;
  343.                 }
  344.             case home_pressed:
  345.                 {  /* HOME means reset the pointer */
  346.                 menucounter = 0;
  347.                 }
  348.             case up_arrow_pressed:
  349.                 {  /*  UP ARROW means go to previous file */
  350.                 menucounter =  qmax(menucounter - 1, 0);
  351.                 break;
  352.                 }
  353.             case end_pressed:
  354.                 {  /*  END means go to last file  */
  355.                 menucounter = filesfound;
  356.                 break;
  357.                 }
  358.             case down_arrow_pressed:
  359.                 {  /* DOWN ARROW means go to next file  */
  360.                 ++menucounter;
  361.                 if (menucounter > filesfound)
  362.                     {
  363.                     menucounter = 0;
  364.                     }
  365.                 break;
  366.                 }
  367.             case right_arrow_pressed:
  368.                 {  /* RIGHT ARROW means "move over one column"  */
  369.                 menucounter = menucounter + WINDOW_DEPTH - 1;
  370.                 if (menucounter > filesfound)
  371.                     {
  372.                     menucounter = filesfound;
  373.                     }
  374.                 break;
  375.                 }
  376.             case left_arrow_pressed:
  377.                 {  /* LEFT ARROW means "move back one column"   */
  378.                 menucounter = qmax(menucounter - WINDOW_DEPTH + 1, 0);
  379.                 break;
  380.                 }
  381.             }
  382.         highlight_area
  383.             (ffr[menucounter].sx,
  384.              ffr[menucounter].sy,
  385.              XINCREMENT - 1);
  386.         }
  387.     }
  388. return(menucounter);
  389. }
  390. /*************************************************************************/
  391. void select_a_file
  392.     (
  393.     qstring search_specification,
  394.     qstring file_that_was_selected
  395.     )
  396. {
  397. /*
  398. This is the driver function for PICKFILE engine and presentation.
  399. */
  400. /*
  401. Set the screen coordinates to the upper left corner of the
  402. presentation box.*/
  403. initialize_coordinates();
  404. /* Initialize the parameter to be returned. */
  405. strcpy(file_that_was_selected, "");
  406. /* Load the file array with those that matched the specification */
  407. filesfound = get_files(search_specification);
  408. /* If anything was found, present the file selection window */
  409. if (filesfound >= 0)
  410.     {
  411.     /*  file sort function goes here  */
  412.     display_file_box();
  413.     initialize_coordinates();
  414.     maincounter = 0;
  415.     maincounter = pick_file_menu();
  416.     if (maincounter <= filesfound)
  417.         {
  418.         strcpy(file_that_was_selected, ffr[maincounter].file_info.ff_name);
  419.         }
  420.     }
  421. qclrscr(bright_white);
  422. }
  423. /*************************  BECIN MAINLINE  *****************************/
  424. main()
  425. {
  426. qint anyint;
  427. qscreen mainscreen;
  428. qint mainx;
  429. qint mainy;
  430.  
  431. /*
  432. Start off by saving the screen at invocation time
  433. */
  434. mainx = qwherex();
  435. mainy = qwherey();
  436. qwindow_save(0, 0, 79, 24, mainscreen);
  437.  
  438. /*
  439. Clear the screen
  440. */
  441. qclrscr(bright_white);
  442.  
  443. /*
  444. Get a file search specification from
  445. the user.
  446. */
  447. qprompt(&filespecification);
  448.  
  449. /*
  450. If the user simply hit carraige return,
  451. then exit, otherwise process the specification.
  452. */
  453. while (filespecification.value[0] > 0)
  454.     {
  455.     qclrscr(bright_white);
  456.     select_a_file(filespecification.value, mainstring);
  457.     qgotoxy(0,25);  /*  hide the cursor  */
  458.     if (mainstring[0] > 0)
  459.         {
  460.         /*
  461.         If the variable "mainstring" contains something,
  462.         then a file was selected.  Here it is simply
  463.         printed out.
  464.         */
  465.         qsnap("You selected ", 29, 23, bright_white);
  466.         qsnap(mainstring, 44, 23, bright_white);
  467.         }
  468.     else
  469.         {
  470.         /*
  471.         if the variable "mainstring" contains nothing,
  472.         one of two conditions occured:
  473.             1.  Nothing matched the file specification; or
  474.             2.  The user hit <Escape> in the selection process.
  475.         */
  476.         qcenter_line("Nothing found or selected", 23, bright_white);
  477.         }
  478.     /*
  479.     Pause here to demonstrate result.
  480.     */
  481.     qcenter_line("Hit a key to continue", 24, bright_white);
  482.     anyint = qreadkbd();
  483.     /*
  484.     Clear the screen, initialize the prompt, and start over.
  485.     */
  486.     qclrscr(bright_white);
  487.     filespecification.value[0] = 0;
  488.     qprompt(&filespecification);
  489.     }
  490. /*
  491. Upon exiting, restore the invocation screen and
  492. cursor position.
  493. */
  494. qwindow_restore(0, 0, 79, 24, mainscreen);
  495. qgotoxy(mainx, mainy - 1);
  496. }
  497. /***********************  END OF PICKFILE  ******************************/
  498.  
  499. /*
  500. Misc files follow...
  501. */
  502.  
  503. /***********************************************/
  504. /*    This is the PROJECT file for PICKFILE.   */
  505. /*    Modify this in the IDE and use the       */
  506. /*    CONTROL KW sequence to save.             */
  507. /*
  508. /*
  509. d:\qlib.lib
  510. pickfile.c
  511. */
  512. /*    End of the PROJECT file for PICKFILE.    */
  513. /***********************************************/
  514.  
  515.  
  516. /**********************************************************************/
  517. /*  This is the QTYPES.C file for PICKFILE.C.  Use this CONTROL KW    */
  518. /*  sequence to save this file into your include subdirectory.        */
  519. /*  The structures are documented elsewhere, and, in fact, this file  */
  520. /*  is optional if the typedefs are included in the 'main' program    */
  521. /********************* begin type declarations ************************/
  522. /*
  523. typedef unsigned char qstring[79];
  524. typedef unsigned char qstring05[5];
  525. typedef unsigned char qstring20[20];
  526. typedef unsigned char qstring40[40];
  527. typedef unsigned char qstring60[60];
  528. typedef unsigned int  qint;
  529. typedef unsigned long qlong;
  530. typedef unsigned char qbyte;
  531. typedef unsigned char qscreen[4096];
  532. typedef struct    
  533.     {
  534.     qstring tag;
  535.     qstring value;
  536.     qint    tagx;
  537.     qint    tagy;
  538.     qint    valx;
  539.     qint    valy;
  540.     qint    vall;
  541.     qbyte   tagf;
  542.     qbyte   tagb;
  543.     qbyte   valf;
  544.     qbyte   valb;
  545.     qint    valr;
  546.     qstring valt;
  547.     qstring vale;
  548.     qbyte   prmx;
  549.     qstring mhea;
  550.     qstring mtra;
  551.     qstring stid;
  552.     qint    poid;
  553.     }
  554.     prompt_record;
  555.  
  556. typedef struct qmenustructure
  557.     {
  558.     qint     screen_x;
  559.     qint     screen_y;
  560.     qint     menu_width;
  561.     qint     foreground;
  562.     qint     background;
  563.     int      option_count;
  564.     qint     prior_choice;
  565.     qstring title;
  566.     qstring option_text[10];
  567.     }
  568.     qmenurecord;
  569. */
  570. /********************* end of type declarations ***********************/
  571. /*                                                                    */
  572. /*       End of the QTYPES.C file for PICKFILE                        */
  573. /**********************************************************************/