home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / C / FS191 / FS1.C < prev    next >
Text File  |  1993-02-24  |  83KB  |  2,670 lines

  1. /* FS1.C
  2.  * handle_dir functions
  3.  * MSC6
  4.  * FS 1.9.1
  5.  * 240293
  6.  * Copyright (C) M. van Breemen, 1993, All rights reserved.
  7.  */
  8.  
  9. #include "FS.H"
  10. #include "XSPAWN.H"
  11.  
  12. /* Prototypes */
  13. int whereis(char *searchstring, int *current_page, int *filenumber );
  14. int find_name(char *fname, int *current_page, int *filenumber);
  15. void outtextm( char *string );
  16. int handle_dir( char *searchstring, char *selected , int safe_mode);
  17. char filename( int filenumber, int mode );
  18. void fileinfo( int filenumber );
  19. char *timestr( unsigned d, char *buf );
  20. char *datestr( unsigned d, char *buf );
  21. void set_cursor( int filenumber );
  22. void clear_remaining( int filenumber );
  23. int extract_directory( char *searchstring );
  24. void show_dir_page( int page );
  25. void kader( void );
  26. void alert( void );
  27. void helpscreen( void );
  28. void aboutscreen( void );
  29. void show_error( char *message );
  30. void wait_sec( int milliseconds );
  31. int rename_file( int filenumber);
  32. int rename_volume_label( int filenumber);
  33. void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr );
  34. int _bios_str( char *p );
  35. void clear_left_button_queue( void );
  36. void clear_right_button_queue( void );
  37. int read_left_button_queue( int *row, int *col );
  38. int read_right_button_queue( int *row, int *col );
  39. void init_mouse( void );
  40. void hide_mouse( void );
  41. void show_mouse( void );
  42. int mouse_button_pressed( void );
  43. void perform_repaint(int current_page, int filenumber);
  44. void c_pgup( int *current_page, int *filenumber);
  45. void c_pgdn( int *current_page, int *filenumber);
  46. void find_first(char chr, int *currentpage, int *filenumber);
  47. void c_home( int *current_page, int *filenumber);
  48. void c_end( int *current_page, int *filenumber);
  49. void c_cup( int *current_page, int *filenumber);
  50. void c_cdn( int *current_page, int *filenumber);
  51. void c_cri( int *current_page, int *filenumber);
  52. void c_cle( int *current_page, int *filenumber);
  53. int _cdecl cmpgle( const void *elem1, const void *elem2 );
  54. unsigned int n_kbhit( void );
  55. int show_file(char *filename);
  56. void movmem(void *src, void *dest, unsigned length);
  57. int getkey(void);
  58. void changecursor(int insmode);
  59. void setcursor(unsigned int shape);
  60. int editstring(int row, int col, char *s, char *illegal, int maxlength);
  61. int edit(char *title, char *string, int length , char *illegal);
  62. int copy_file( int filenumber);
  63. int make_directory( void );
  64. int ed_attributes( int filenumber);
  65. int copy( char *oldname, char *newname );
  66. char *saveScrn(void);
  67. char *restScrn(char *saveArea);
  68. void show_path( void );
  69. int valid_filename( char *newname);
  70. int freespace( char *linebuf );
  71. void working( int mode );
  72. void shadebox( short r1, short c1, short r2, short c2 );
  73. void shadechar( int row, int col );
  74. char *set_working_drive_and_dir( char *full_filename );
  75. int find_in_file( char *filename , char *string, int ignore_case);
  76. void do_dir(char *path);
  77. void find_parent( int *current_page, int *filenumber, char *searchstring);
  78. int getdrv(void);
  79. int chdrv(int drive);
  80. int drvalid(int drive);
  81. char *FilGetVolid( unsigned char Drive );
  82. int FilSetVolid( unsigned char Drive, char *Volid );
  83. int FilDelVolid( unsigned char Drive );
  84. void ScrPutS(char *String, unsigned char Attr,
  85.          unsigned char Row, unsigned char Col);
  86. int ask_drive_number(char *message);
  87.  
  88. /* global variables */
  89.  
  90. unsigned short int checkpoint1[3]= { 0xFEFF, 0xFCFD, 0xFAFB }; /* Backword FFFEFDFCFBFA */
  91. short int screen_bg_color     = BLUE;
  92. short int file_color         = WHITE;
  93. short int directory_color     = YELLOW;
  94. short int cursor_bg_color     = RED;
  95. short int cursor_file_color     = WHITE;             /* 14 bytes color info */
  96. short int cursor_directory_color = YELLOW;
  97. short int info_bg_color         = GREEN;
  98. short int info_text_color     = BRIGHTWHITE;
  99. short int error_text_color     = LIGHTRED;
  100. short int prompt_text_color     = YELLOW;
  101. short int hidden_file_color     = BRIGHTWHITE;
  102. short int hidden_directory_color = LIGHTGREEN;
  103. short int volume_label_color     = CYAN;
  104. short int cursor_hidden_file_color     = BRIGHTWHITE;
  105. short int cursor_hidden_directory_color= LIGHTGREEN;
  106. short int cursor_volume_label_color    = CYAN;
  107.  
  108. unsigned short int checkpoint2[3]= { 0xFBFA, 0xFDFC, 0xFFFE }; /* Backword FAFBFCFDFEFF */
  109.  
  110. static struct {                /* FCB for volume label functions */
  111.           unsigned char Extcode;
  112.           char Res1[5];
  113.           unsigned char Code;
  114.           unsigned char OldDrive;
  115.           char OldName[11];
  116.           char Res2[5];
  117.           char NewName[11];
  118.           char Res3[9];
  119.           } DirFcb = {0xFF,"",0x10,0,"","","",""},
  120.         VolFcb = {0xFF,"",0x08,0,"???????????","","",""};
  121.  
  122. static struct {                /* DTA for volume label functions */
  123.           char Res1[8];      /* reserved */
  124.           char OldVolid[11]; /* filled in by DOS */
  125.           char Res2[5];      /* reserved */
  126.           char NewVolid[11]; /* used by FilSetVolid */
  127.           char Res3[9];      /* reserved */
  128.           } Dta;
  129.  
  130. int number_of_files;    /* number of files found */
  131.  
  132. typedef struct find_t_small {
  133.                 char name [13];
  134.                 char attrib;
  135.                 } FIND_T_SMALL;
  136.  
  137. FIND_T_SMALL *find;    /* pointer to the file info structures */
  138. int mouse_present;    /* boolean is there a mouse ? */
  139. int mouse_row=0;    /* mouse position, NOT screen rows and columns */
  140. int mouse_col=0;
  141. int max_files;          /* maximal number of accessible files per directory or root, defaults to 456 */
  142. int dos_error;        /* set by error handler */
  143. int dos_retries;    /* set by error handler */
  144.  
  145. /* volume label functions taken from 'Systems Programming in Microsoft C, Michael J. Young */
  146.  
  147. char *FilGetVolid( unsigned char Drive )
  148. {
  149.     int ErrorCode;
  150.     union REGS Reg;
  151.  
  152.     Reg.x.dx = (unsigned int) &Dta;
  153.     Reg.h.ah = 0x1A;
  154.     int86(0x21, &Reg, &Reg);
  155.     VolFcb.OldDrive = Drive;
  156.     Reg.x.dx = (unsigned int) &VolFcb;
  157.     Reg.h.ah = 0x11;
  158.     int86(0x21, &Reg, &Reg);
  159.  
  160.     ErrorCode = Reg.h.al;
  161.     if (ErrorCode == 0) return (Dta.OldVolid);
  162.     else return (NULL);
  163. }
  164.  
  165. int FilSetVolid( unsigned char Drive, char *Volid )
  166. {
  167.     register int i;
  168.     int ErrorCode;
  169.     union REGS Reg;
  170.  
  171.     if (FilGetVolid(Drive)==NULL)
  172.     {
  173.     for (i=0;i<11;++i)
  174.         if (*Volid=='\0') VolFcb.OldName[i]= ' ';
  175.         else VolFcb.OldName[i]= *Volid++;
  176.     Reg.x.dx=(unsigned int) &VolFcb;
  177.     Reg.h.ah=0x16;
  178.     int86(0x21, &Reg, &Reg);
  179.  
  180.     ErrorCode=Reg.h.al;
  181.         if (ErrorCode==0) return (NOERROR);
  182.         else return (NOCREAT);
  183.     }
  184.     else
  185.     {
  186.     for (i=0;i<11;++i)
  187.         if (*Volid=='\0') Dta.NewVolid[i]= ' ';
  188.         else Dta.NewVolid[i]= *Volid++;
  189.     Reg.x.dx=(unsigned int) &Dta;
  190.     Reg.h.ah=0x17;
  191.     int86(0x21, &Reg, &Reg);
  192.  
  193.     ErrorCode=Reg.h.al;
  194.         if (ErrorCode==0) return (NOERROR);
  195.         else return (NOREN);
  196.     }
  197. }
  198.  
  199. int FilDelVolid( unsigned char Drive )
  200. {
  201.     int ErrorCode;
  202.     union REGS Reg;
  203.  
  204.     if (FilGetVolid ( Drive )==NULL)
  205.     {
  206.     return (NOVOL);
  207.     }
  208.     else
  209.     {
  210.     Reg.x.dx=(unsigned int) &Dta;
  211.     Reg.h.ah=0x13;
  212.     int86(0x21, &Reg,&Reg);
  213.  
  214.     ErrorCode=Reg.h.al;
  215.         if (ErrorCode==0) return (NOERROR);
  216.         else return (NODEL);
  217.     }
  218. }
  219.  
  220. /*---------------------------------------------------------------------------*/
  221. /*   FF    Routines taken from FFF 3.4.5, a public domain program to search files
  222.  *    Author:    Don A. Williams                                             *
  223.  *        CompuServ -                                                 *
  224.  *        Genie      - DON-WILL                                         *
  225. */
  226.  
  227.  
  228. #define U_ESC     1
  229. #define U_SELECT 2
  230. #define U_GOTO 3
  231.  
  232. #define FIND_FIRST(Name,Block,Attrib) _dos_findfirst(Name, Attrib, Block);
  233. #define FIND_NEXT(Block) _dos_findnext(Block);
  234. #define DIR_ENTRY find_t    /* Name of the directory entry structure    */
  235. #define D_ATTRIB attrib        /* Attribute field in directory entry        */
  236. #define D_NAME name        /* File name field in directory entry        */
  237.  
  238.  
  239. typedef struct QueEntry {
  240.               struct QueEntry *Next;
  241.               char    *Body;
  242.             } QUE_ENTRY;
  243.  
  244. typedef struct QueDef {
  245.             QUE_ENTRY *Head, *Current;
  246.             int       Count;
  247.               } QUE_DEF;
  248.  
  249. /* Function prototypes      */
  250.  
  251. int        fff( char *fpattern, char *sstring, int ignore_case);
  252. void        InitQueue (QUE_DEF *Q);
  253. QUE_ENTRY    *Enque (QUE_DEF *Q, void *Body);
  254. int        WalkTree (QUE_DEF * Q, char *sstring , int ignore_case);
  255. int             SearchQ (char *Str);
  256. int             Match (char *Str, char *Pat);
  257. static int    I_Match (char *Str, char *Pat);
  258. static int    S_Match (char *S, char *P, int Anchor);
  259.  
  260. /*----------------------------------------------------------------------*/
  261.  
  262. QUE_DEF     PatQue;
  263. char        T_Path[_MAX_PATH];            /* Temporary directory path to search    */
  264. char        V_Path[_MAX_PATH];            /* Selected file */
  265.  
  266. /**************************************************************************
  267.  Find and put cursor on file with matching name
  268. */
  269. int find_name(char *fname, int *current_page, int *filenumber)
  270. {
  271.      register int counter;
  272.      int result=FAILURE;
  273.      if (!number_of_files) return (result);
  274.      for (counter=1;counter<=number_of_files;counter++)
  275.        if (!strcmp(find[counter].name,fname))
  276.        {
  277.        result=SUCCESS;
  278.        break;
  279.        }
  280.      if (result==SUCCESS)
  281.      {
  282.      *filenumber=counter;
  283.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  284.      }
  285.      return (result);
  286. }
  287.  
  288. /*************************************************************************
  289.  hide mouse, _outtext, show_mouse
  290. */
  291. void outtextm( char *string )
  292. {
  293.     hide_mouse();
  294.     _outtext(string);
  295.     show_mouse();
  296. }
  297.  
  298. /*************************************************************************
  299.   Returns F for normal file, D for directory, V for volume label, H for hidden file.
  300.   Displays Filename if mode != NOREPAINT
  301. */
  302. char filename( int filenumber, int mode )
  303. {
  304.     char type, namebuf[14];
  305.     static struct videoconfig vc={0,0,0,0,0,0,0,0,0,0,0};
  306.  
  307.     if (!vc.numcolors) _getvideoconfig( &vc ); /* initialize on first call */
  308.  
  309.     if (vc.mode==_TEXTMONO)
  310.     sprintf( namebuf, "%c%-12s",
  311.          (find[filenumber].attrib & _A_HIDDEN) ? '' : ' ',
  312.          find[filenumber].name);
  313.     else sprintf( namebuf, "%-12s ",find[filenumber].name);
  314.  
  315.     if( find[filenumber].attrib & _A_SUBDIR )       type='D';  /* directory */
  316.     else if( find[filenumber].attrib & _A_VOLID )  type='V';  /* volume label */
  317.      else type='F';                          /* normal file */
  318.  
  319.     switch (mode)
  320.     {
  321.     case NOREPAINT: break;
  322.     case CURSOR: set_cursor( filenumber );
  323.          switch (type)
  324.          {
  325.             case 'D': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) cursor_hidden_directory_color );
  326.                   else _settextcolor( (short) cursor_directory_color );
  327.                   break;
  328.             case 'V': _settextcolor( (short) cursor_volume_label_color );
  329.                   break;
  330.             case 'F': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) cursor_hidden_file_color );
  331.                   else _settextcolor( (short) cursor_file_color );
  332.                   break;
  333.          }
  334.          _setbkcolor( (long) cursor_bg_color );
  335.          outtextm( namebuf );
  336.          _setbkcolor( (long) screen_bg_color );
  337.          break;
  338.     case NORMAL: set_cursor( filenumber );
  339.          switch (type)
  340.          {
  341.             case 'D': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) hidden_directory_color );
  342.                   else _settextcolor( (short) directory_color );
  343.                   break;
  344.             case 'V': _settextcolor( (short) volume_label_color );
  345.                   break;
  346.             case 'F': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) hidden_file_color );
  347.                   else _settextcolor( (short) file_color );
  348.                   break;
  349.          }
  350.          _setbkcolor( (long) screen_bg_color );
  351.          outtextm( namebuf );
  352.          break;
  353.     }
  354.     return (type);
  355. }
  356.  
  357. /***************************************************************************
  358.  Displays information about a file.
  359. */
  360. void fileinfo( int filenumber )
  361. {
  362.     char timebuf[6], datebuf[9], attrbuf[5], namebuf[13], sizebuf[9], type;
  363.     struct find_t pfind;
  364.     short x,y,c;
  365.     char b[8*29+10];                    /* Buffer for string */
  366.     char *savedscreen;
  367.     int key=0;
  368.  
  369.     /* get full file information */
  370.     if (_dos_findfirst( find[filenumber].name, 0xffff, &pfind )) /* not succeeded, get out */
  371.     {
  372.        show_error("Cannot get the information for this file ");
  373.        return;
  374.     }
  375.     savedscreen=saveScrn();
  376.  
  377.     y = ((25 -    8) / 2) + 1;     /* 8 lines, add 1 to center in FS window */
  378.     x = ((80 - 28) / 2);     /* 28 visible characters per line */
  379.  
  380.     datestr( pfind.wr_date, datebuf );
  381.     timestr( pfind.wr_time, timebuf );
  382.  
  383.     sprintf( attrbuf, "%c%c%c%c",
  384.         (pfind.attrib & _A_RDONLY) ? 'R' : '_',
  385.         (pfind.attrib & _A_HIDDEN) ? 'H' : '_',
  386.         (pfind.attrib & _A_SYSTEM) ? 'S' : '_',
  387.         (pfind.attrib & _A_ARCH)     ? 'A' : '_' );
  388.  
  389.     sprintf( sizebuf, "%ld", pfind.size);
  390.  
  391.     sprintf( namebuf, "%-12s", pfind.name);
  392.  
  393.     if( pfind.attrib & _A_SUBDIR )     type='D';  /* directory */
  394.     else if( pfind.attrib & _A_VOLID )     type='V';  /* volume label */
  395.      else type='F';                    /* normal file */
  396.  
  397.     _settextcolor( (short) info_text_color );
  398.     _setbkcolor( (long) info_bg_color );
  399.     /* Use text window to place output in middle of screen */
  400.     /* The window is 1 position larger than the output string. */
  401.     _settextwindow( y, x, y + 8, x + 28 );
  402.     shadebox(     y, x, y + 8 - 1 , x + 28 - 1 );
  403.  
  404.     /* Write all information to a string, then output string. */
  405.     c  = sprintf( b    , "╔══════════════════════════╗\n");
  406.     c += sprintf( b + c, "║ Filename  : %-12s ║\n",namebuf);
  407.     c += sprintf( b + c, "║ Size      : %-12s ║\n",sizebuf);
  408.     c += sprintf( b + c, "║ Date      : %-12s ║\n",datebuf);
  409.     c += sprintf( b + c, "║ Time      : %-12s ║\n",timebuf);
  410.     c += sprintf( b + c, "║ Attributes: %-12s ║\n",attrbuf);
  411.     c += sprintf( b + c, "║ Type      : ");
  412.     switch (type)
  413.     {
  414.     case 'F': c += sprintf( b + c, "%-12s ║\n","File");
  415.           break;
  416.     case 'D': c += sprintf( b + c, "%-12s ║\n","Directory");
  417.           break;
  418.     case 'V': c += sprintf( b + c, "%-12s ║\n","Volume label");
  419.           break;
  420.     }
  421.     c += sprintf( b + c, "╚══════════════════════════╝\n");
  422.     outtextm( b );
  423.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ ;
  424.     _settextwindow( 3, 1, 23, 80 );
  425.     _setbkcolor( (long) screen_bg_color );
  426.     savedscreen=restScrn(savedscreen);
  427.     if ((key & 0x00FF)==ESC) getkey();    /* trash ESC */
  428. }
  429.  
  430. /***************************************************************************
  431.  * Takes unsigned time in the format:             fedcba9876543210
  432.  * s=2 sec incr, m=0-59, h=23                       hhhhhmmmmmmsssss
  433.  * Changes to a 5-byte string (ignore seconds):     hh:mm
  434.  */
  435. char *timestr( unsigned t, char *buf )
  436. {
  437.     int h = (t >> 11) & 0x1f, m = (t >> 5) & 0x3f;
  438.  
  439.     sprintf( buf, "%2.2d:%02.2d", h, m );    return buf;
  440. }
  441.  
  442. /**************************************************************************
  443.  * Takes unsigned date in the format:              fedcba9876543210
  444.  * d=1-31, m=1-12, y=0-119 (1980-2099)              yyyyyyymmmmddddd
  445.  * Changes to a 8-byte string:                      mm/dd/yy
  446.  */
  447. char *datestr( unsigned d, char *buf )
  448. {
  449.     sprintf( buf, "%2.2d/%02.2d/%02.2d",
  450.          d & 0x1f, (d >> 5) & 0x0f, (d >> 9) + 80 );
  451.     return buf;
  452. }
  453.  
  454. /***************************************************************************
  455.  * Calculate page, line, column from filenumber and sets cursor position
  456.  * Displays page number if this is changed
  457.  * pagelayout: 6 columns of 19 files per page, 114 files per page,
  458.  *             starting at window line 1, column width 13 (position 1,14,27...)
  459.  * filenumber= 1,2,...
  460.  * page      = 0,1,...
  461.  * line      = 2,3,...,21
  462.  * column    = 2,15,28,41,54,67
  463.  */
  464. void set_cursor( int filenumber )
  465. {
  466.     int line, column, relfilenumber, old_page, old_max_page;
  467.     char linebuf[10];
  468.     static int page=-1;
  469.     static int max_page=-1;
  470.     old_page=page;
  471.     old_max_page=max_page;
  472.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  473.     line=((filenumber%19) ? filenumber%19 : 19) + 1;
  474.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  475.     relfilenumber=(filenumber - page*114);
  476.     column=((relfilenumber%19) ? relfilenumber/19 : relfilenumber/19 - 1) * 13 + 2;
  477.     if (old_page!=page || old_max_page!=max_page)
  478.     {
  479.     sprintf(linebuf,"%d/%d╞══",page+1,max_page+1);
  480.     _settextposition( 1, 72 );
  481.     _settextcolor( (short) file_color );
  482.     _setbkcolor( (long) screen_bg_color );
  483.     outtextm(linebuf);
  484.     }
  485.     _settextposition( line, column );
  486. }
  487.  
  488.  
  489. /**************************************************************************
  490.   Clear remaining directory page by displaying blank names, starting with
  491.   filenumber+1
  492.  */
  493. void clear_remaining( int filenumber )
  494. {
  495.     register int line, column, relfilenumber;
  496.     int page;
  497.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  498.     relfilenumber=(filenumber - page*114);
  499.     _setbkcolor( (long) screen_bg_color );
  500.     _settextcolor( (short) file_color );
  501.     while (relfilenumber < 114 )
  502.     {
  503.     filenumber++;
  504.     relfilenumber++;
  505.     line=((filenumber%19) ? filenumber%19 : 19) + 1;
  506.     column=((relfilenumber%19) ? relfilenumber/19 : relfilenumber/19 - 1) * 13 + 2;
  507.     _settextposition( line, column );
  508.     outtextm( "             " );
  509.     }
  510. }
  511.  
  512. /***************************************************************************
  513.  * Compares and returns greater than (1), less than (-1), or equal to (0).
  514.  * This function is called by qsort.
  515.  */
  516.  
  517. int _cdecl cmpgle( const void *elem1, const void *elem2 )
  518. {
  519.     const struct find_t_small *e1, *e2;
  520.     e1=elem1;
  521.     e2=elem2;
  522.     return strcmp(e1->name,e2->name);
  523. }
  524.  
  525. /***************************************************************************
  526.  Fills find structure and sets number_of_files global. Filters files with
  527.  searchstring mask. Skips "." directory and volume label. Sorts find structure
  528. */
  529. int extract_directory( char *searchstring )
  530. {
  531.     struct find_t findtemp;
  532.     char type;
  533.     number_of_files=0;
  534.     working(TRUE);
  535.     /* Find first matching file, then find additional matches. */
  536.     if( !_dos_findfirst( "*.*\0", _A_ARCH | _A_HIDDEN | _A_NORMAL | _A_RDONLY |
  537.                   _A_SUBDIR | _A_SYSTEM | _A_VOLID, &findtemp ) )
  538.     {
  539.        if( findtemp.attrib & _A_SUBDIR ) type='D';      /* directory */
  540.        else if( findtemp.attrib & _A_VOLID ) type='V'; /* volume label */
  541.         else type='F'; /* normal file (and hidden file) */
  542.        if (findtemp.name[0]=='.' && findtemp.name[1]=='\0' && type== 'D') type='N'; /* null dir */
  543.        if (type=='F' || type=='D' || type=='V')
  544.        {
  545.      strcpy(find[++number_of_files].name,findtemp.name);
  546.      find[number_of_files].attrib=findtemp.attrib;
  547.        }
  548.        if (type=='F' && strlen(searchstring) && !Match(findtemp.name,searchstring)) number_of_files--;
  549.        while( !_dos_findnext( &findtemp ) && (number_of_files < max_files ))
  550.        {
  551.      if( findtemp.attrib & _A_SUBDIR ) type='D';    /* directory */
  552.      else if( findtemp.attrib & _A_VOLID ) type='V'; /* volume label */
  553.           else type='F'; /* normal file */
  554.      if (findtemp.name[0]=='.' && findtemp.name[1]=='\0' && type== 'D') type='N'; /* null dir */
  555.      if (type=='F' || type=='D' || type=='V')
  556.      {
  557.        strcpy(find[++number_of_files].name,findtemp.name);
  558.        find[number_of_files].attrib=findtemp.attrib;
  559.      }
  560.      if (type=='F' && strlen(searchstring) && !Match(findtemp.name,searchstring)) number_of_files--;
  561.        }
  562.     }
  563.     working(FALSE);
  564.     if (!number_of_files)
  565.     {
  566.     show_error( "No files found " );
  567.     find[1].attrib='\0';
  568.     find[1].name[0]='\0';
  569.     return FAILURE;
  570.     }
  571.  
  572.     qsort( (void *) (&(find[1])), (size_t) number_of_files,
  573.        (size_t) sizeof(FIND_T_SMALL), cmpgle);
  574.  
  575.     return SUCCESS;
  576. }
  577.  
  578. /****************************************************************************
  579.  Display the filenames of one page
  580. */
  581. void show_dir_page( int page )
  582. {
  583.     register int filenumber;
  584.     for (filenumber=1 + page*114; filenumber<=(114 + page*114) && filenumber<=number_of_files; filenumber++)
  585.     {
  586.     filename( filenumber, NORMAL );
  587.     }
  588.     clear_remaining( filenumber-1 );
  589. }
  590.  
  591. /****************************************************************************
  592.  Draw the border lines
  593. */
  594. void kader( void )
  595. {
  596.     int line;
  597.     _settextwindow( 3, 1, 24, 80 );  /* prevent scroll-up */
  598.     _settextcolor( (short) file_color );
  599.     _settextposition( 1, 1 );
  600.     hide_mouse();
  601.     _outtext("╔════════════╡   ╞════════════════════════════════════════════════════╡   ╞════╗");
  602.     for (line=2;line<=20;line++)
  603.     {
  604.     _settextposition( line, 1 );
  605.     _outtext("║");
  606.     _settextposition( line, 80 );
  607.     _outtext("║");
  608.     }
  609.     _settextposition( 21, 1 );
  610.     _outtext("╚══════════════════════════════════════════════════════════════════════════════╝");
  611.     if (number_of_files==max_files)
  612.     {
  613.      _settextposition( 21,3 );
  614.      _outtext( "File table full");
  615.     }
  616.     show_mouse();
  617.     _settextwindow( 3, 1, 23, 80 );
  618. }
  619.  
  620. /**************************************************************************
  621.  Beep
  622. */
  623. void alert( void )
  624. {
  625.     _bios_str( "\007" );
  626. } /* end alert */
  627.  
  628. /****************************************************************************
  629.  * Handler to deal with hard error codes. Since DOS is not reentrant,
  630.  * it is not safe to use DOS calls for doing I/O within the DOS Critical
  631.  * Error Handler (int 24h) used by _harderr. Therefore, screen output and
  632.  * keyboard input must be done through the BIOS.
  633.  */
  634. void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr )
  635. {
  636.     int ch;
  637.     unsigned char row=3;
  638.     int itel,itel2;
  639.  
  640.     static char buf[200], tmpbuf[10];
  641.  
  642.     /* save error code */
  643.     dos_error=doserr;
  644.  
  645.     strcpy( buf, " Device error code: " );
  646.     strcat( buf, itoa( deverr, tmpbuf, 10 ) );
  647.     strcat( buf, " " );
  648.     ScrPutS( buf, 0x0f, row++, 1);
  649.     strcpy( buf, " DOS error code   : " );
  650.     strcat( buf, itoa( doserr, tmpbuf, 10 ) );
  651.     strcat( buf, " " );
  652.     ScrPutS( buf, 0x0f, row++, 1);
  653.     strcpy( buf, " (F) for Fail, any other key for Retry ? " );
  654.     ScrPutS( buf, 0x0f, row++, 1);
  655.  
  656.     _bios_str( "\007" );
  657.     ch = _bios_keybrd( _KEYBRD_READ ) & 0x00ff;
  658.  
  659.     switch( ch )
  660.     {
  661.     case 'F':
  662.     case 'f':    /* Return to DOS with error code */
  663.         dos_retries=0;
  664.         for (itel=3;itel<=6;itel++)      /* blank screen segment */
  665.         for (itel2=1;itel2<=41;itel2++)
  666.             ScrPutS( " ", ((unsigned char) (screen_bg_color * 16)),
  667.                   (unsigned char) itel,(unsigned char) itel2);
  668.         _hardretn( doserr );
  669.     default:    /* Try again */
  670.         dos_retries++;
  671.         strcpy( buf, " Retrying");
  672.         for (itel=0;itel<dos_retries;itel++) strcat( buf,".");
  673.         ScrPutS( buf, 0x0f, row++, 1);
  674.         _hardresume( _HARDERR_RETRY );
  675.     }
  676. }
  677.  
  678.  
  679. /****************************************************************************
  680.  * Display a string using BIOS interrupt 0x0e (Write TTY). Return length
  681.  * of string displayed.
  682.  */
  683. int _bios_str( char *p )
  684. {
  685.     union REGS inregs, outregs;
  686.     char *start = p;
  687.  
  688.     inregs.h.ah = 0x0e;
  689.     for( ; *p; p++ )
  690.     {
  691.     inregs.h.al = *p;
  692.     int86( 0x10, &inregs, &outregs );
  693.     }
  694.     return p - start;
  695. }
  696.  
  697. /*************************************************************************
  698.  Display an error message, wait one second and blank out message
  699. */
  700. void show_error( char *message )
  701. {
  702.     alert();
  703.     _settextcolor( (short) error_text_color );
  704.     _settextposition( 23,1 );
  705.     outtextm( message );
  706.     wait_sec(1000);
  707.     _settextcolor( (short) file_color );
  708.     _settextposition( 23, 1 );
  709.     outtextm("╚══════════════════════════════════════════════════════════════════════════════");
  710.     _settextposition(1,1);
  711. }
  712.  
  713. /*************************************************************************
  714.  wait, suspend program
  715. */
  716. void wait_sec( int milliseconds )
  717. {
  718.     clock_t cstart;
  719.     cstart=clock();
  720.     while ( (clock()-cstart) < (clock_t) (CLOCKS_PER_SEC/1000) * (clock_t) milliseconds) ;
  721. }
  722.  
  723. /****************************************************************************
  724.  Displays help information
  725. */
  726. void helpscreen( void )
  727. {
  728.     short x,y;
  729.     int key=0;
  730.     char b[(18*55)+10]={          /* Buffer for string */
  731.              "╔════════════════════════════════════════════════════╗\n"
  732.              "║  FS 1.9.1  (C) Copyright M.C.J. van Breemen, 1993  ║\n"
  733.              "╟────────────────────────────────────────────────────╢\n"
  734.              "║ \x1B\x17\x1A    Move cursor       Del Delete file/dir/label ║\n"
  735.              "║ Return Select file /     I   File information      ║\n"
  736.              "║        Change directory  D   Select drive          ║\n"
  737.              "║ PgUp   Previous screen   R   Rename file/dir/label ║\n"
  738.              "║ PgDn   Next screen       S   Show file             ║\n"
  739.              "║ Home   First file        C   Copy file             ║\n"
  740.              "║ End    Last file         M   Change selection mask ║\n"
  741.              "║ T      Top directory     X   Temporary exit to DOS ║\n"
  742.              "║ U      Up one dir.       E   Execute file          ║\n"
  743.              "║ Alt-AZ Go to filename    A   Change attributes     ║\n"
  744.              "║ /      Refresh screen    N   Create directory      ║\n"
  745.              "║ L      Exit & keep dir.  V   Create volume label   ║\n"
  746.              "║ Esc    Exit / Cancel     F   Disk space free       ║\n"
  747.              "║ P      About the program W   Where is file         ║\n"
  748.              "╚════════════════════════════════════════════════════╝\n"
  749.                };
  750.     char *savedscreen;
  751.  
  752.     savedscreen=saveScrn();
  753.  
  754.     y = ((25 - 18) / 2) + 1;    /* 18 lines */
  755.     x =  (80 - 54) / 2;        /* 54 visible characters per line */
  756.     _settextcolor( (short) info_text_color );
  757.     _setbkcolor( (long) info_bg_color );
  758.  
  759.     /* Use text window to place output in middle of screen. */
  760.     _settextwindow( y, x, y + 18, x + 54 );
  761.     shadebox(     y, x, y + 18 - 1 , x + 54 - 1 );
  762.     outtextm( b );
  763.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ ;
  764.     _settextwindow( 3, 1, 23, 80 );
  765.     _setbkcolor( (long) screen_bg_color );
  766.     savedscreen=restScrn(savedscreen);
  767.     if ((key & 0x00FF)==ESC) getkey();    /* trash ESC */
  768. }
  769.  
  770. /****************************************************************************
  771.  Displays program information
  772. */
  773. void aboutscreen( void )
  774. {
  775.     short x,y;
  776.     int key=0;
  777.     char b[(15*53)+10]={          /* Buffer for string */
  778.              "╔══════════════════════════════════════════════════╗\n"
  779.              "║                                                  ║\n"
  780.              "║           File Selector, Version 1.9.1           ║\n"
  781.              "║     Copyright (C) 1993 by M.C.J. van Breemen     ║\n"
  782.              "║                                                  ║\n"
  783.              "║             Release date: 24-FEB-1993            ║\n"
  784.              "║                                                  ║\n"
  785.              "║          Program designed and written by:        ║\n"
  786.              "║                                                  ║\n"
  787.              "║             Maarten van Breemen                  ║\n"
  788.              "║             Combinatiepolder 13                  ║\n"
  789.              "║             5235 TR 's-Hertogenbosch             ║\n"
  790.              "║             The Netherlands                      ║\n"
  791.              "║                                                  ║\n"
  792.              "╚══════════════════════════════════════════════════╝\n"
  793.                };
  794.     char *savedscreen;
  795.  
  796.     savedscreen=saveScrn();
  797.  
  798.     y = ((25 - 15) / 2) + 1;    /* 15 lines */
  799.     x =  (80 - 52) / 2;        /* 52 visible characters per line */
  800.  
  801.     _settextcolor( (short) info_text_color );
  802.     _setbkcolor( (long) info_bg_color );
  803.  
  804.     /* Use text window to place output in middle of screen. */
  805.     _settextwindow( y, x, y + 15, x + 52 );
  806.     shadebox( y, x, y + 15 - 1, x + 52 - 1 );
  807.     outtextm( b );
  808.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ ;
  809.     _settextwindow( 3, 1, 23, 80 );
  810.     _setbkcolor( (long) screen_bg_color );
  811.     savedscreen=restScrn(savedscreen);
  812.     if ((key & 0x00FF)==ESC) getkey();    /* trash ESC */
  813. }
  814.  
  815. /*************************************************************************
  816.  Mouse
  817. */
  818. void clear_left_button_queue( void )
  819. {
  820.     union REGS in_regs, out_regs;
  821.     in_regs.x.bx = 0;   /* Clear left button queue */
  822.     in_regs.x.ax = 5;
  823.     int86(0x33, &in_regs, &out_regs);
  824. }
  825.  
  826. /*************************************************************************
  827.  Mouse
  828. */
  829. void clear_right_button_queue( void )
  830. {
  831.     union REGS in_regs, out_regs;
  832.     in_regs.x.bx = 1;    /* Clear right button queue */
  833.     in_regs.x.ax = 5;
  834.     int86(0x33, &in_regs, &out_regs);
  835. }
  836.  
  837. /*************************************************************************
  838.  Mouse
  839.  * Read left button queue
  840.  * Return 0 if no left button pressed
  841.  *        1 if pressed but on new position
  842.  *        2 if re-pressed on old position within 0.75 second
  843.  */
  844. int read_left_button_queue( int *row, int *col )
  845. {
  846.     union REGS in_regs, out_regs;
  847.     static int lastrow, lastcol, number_times;
  848.     static clock_t cstart;
  849.  
  850.     in_regs.x.bx = 0;
  851.     in_regs.x.ax = 5;
  852.     int86(0x33, &in_regs, &out_regs);
  853.  
  854.     number_times = out_regs.x.bx;
  855.     *row = out_regs.x.dx / 8 + 1;
  856.     *col = out_regs.x.cx / 8 + 1;
  857.     if (!number_times) return 0;
  858.     if (lastrow==*row && lastcol==*col && ((clock()-cstart) < (clock_t) CLOCKS_PER_SEC*2/3))
  859.     {
  860.     clear_left_button_queue();
  861.     cstart=clock();
  862.     return 2;
  863.     }
  864.     lastrow = *row;
  865.     lastcol = *col;
  866.     clear_left_button_queue();
  867.     cstart=clock();
  868.     return 1;
  869. }
  870. /*************************************************************************
  871.  Mouse
  872.  * Read right button queue
  873.  * Return 0 if no right button pressed
  874.  *        1 if pressed but on new position
  875.  *        2 if re-pressed on old position within 0.75 second
  876.  */
  877. int read_right_button_queue( int *row, int *col )
  878. {
  879.     union REGS in_regs, out_regs;
  880.     static int lastrow, lastcol, number_times;
  881.     static clock_t cstart;
  882.  
  883.     in_regs.x.bx = 1;
  884.     in_regs.x.ax = 5;
  885.     int86(0x33, &in_regs, &out_regs);
  886.  
  887.     number_times = out_regs.x.bx;
  888.     *row = out_regs.x.dx / 8 + 1;
  889.     *col = out_regs.x.cx / 8 + 1;
  890.     if (!number_times) return 0;
  891.     if (lastrow==*row && lastcol==*col && ((clock()-cstart) < (clock_t) CLOCKS_PER_SEC*2/3))
  892.     {
  893.     clear_right_button_queue();
  894.     cstart=clock();
  895.     return 2;
  896.     }
  897.     lastrow = *row;
  898.     lastcol = *col;
  899.     clear_right_button_queue();
  900.     cstart=clock();
  901.     return 1;
  902. }
  903.  
  904. /*********************************************************************88
  905.  Mouse
  906. */
  907. void init_mouse( void )
  908. {
  909.     union REGS in_regs, out_regs;
  910.     int top, bottom, left, right;
  911.     in_regs.x.ax = 0;           /* Initialize mouse */
  912.     int86(0x33, &in_regs, &out_regs);
  913.     if (!out_regs.x.ax)
  914.     {
  915.      mouse_present=FALSE;
  916.      return;
  917.     }    else mouse_present=TRUE;
  918.     right = 79;  /* Restrict cursor horizontally */
  919.     left = 2;
  920.     in_regs.x.cx = 8 * (right - 1);
  921.     in_regs.x.dx = 8 * (left - 1);
  922.     in_regs.x.ax = 7;
  923.     int86(0x33, &in_regs, &out_regs);
  924.     top = 4;             /* Restrict cursor vertically */
  925.     bottom = 22;
  926.     in_regs.x.cx = 8 * (top - 1);
  927.     in_regs.x.dx = 8 * (bottom - 1);
  928.     in_regs.x.ax = 8;
  929.     int86(0x33, &in_regs, &out_regs);
  930.     clear_left_button_queue();
  931.     if (mouse_col)       /* re-position mouse */
  932.     {
  933.        in_regs.x.cx = mouse_col;
  934.        in_regs.x.dx = mouse_row;
  935.        in_regs.x.ax = 4;
  936.        int86(0x33, &in_regs, &out_regs);
  937.     }
  938.     show_mouse();
  939. }
  940.  
  941. /***************************************************************************8
  942.  Mouse
  943. */
  944. void hide_mouse( void )
  945. {
  946.     union REGS in_regs, out_regs;
  947.     if (!mouse_present) return;
  948.     /* first save mouse position for possible future mouse_init */
  949.     in_regs.x.ax = 3;
  950.     int86(0x33, &in_regs, &out_regs);
  951.     mouse_col = out_regs.x.cx;
  952.     mouse_row = out_regs.x.dx;
  953.  
  954.     in_regs.x.ax = 2;   /* Hide mouse cursor */
  955.     int86(0x33, &in_regs, &out_regs);
  956. }
  957.  
  958. /***************************************************************************8
  959.  Mouse
  960. */
  961. void show_mouse( void )
  962. {
  963.     union REGS in_regs, out_regs;
  964.     if (!mouse_present) return;
  965.     in_regs.x.ax = 1;           /* Show mouse cursor */
  966.     int86(0x33, &in_regs, &out_regs);
  967. }
  968.  
  969. /*************************************************************************
  970.  Mouse
  971.  * Status mouse buttons
  972.  * Return 0 if no button pressed
  973.  *        else something is in queue
  974.  */
  975. int mouse_button_pressed( void )
  976. {
  977.     union REGS in_regs, out_regs;
  978.  
  979.     in_regs.x.bx = 0;
  980.     in_regs.x.ax = 3;
  981.     int86(0x33, &in_regs, &out_regs);
  982.     return( out_regs.x.bx );
  983. }
  984.  
  985. /***************************************************************************
  986.  Common redraw functions
  987. */
  988. void perform_repaint(int current_page, int filenumber)
  989. {
  990.     char linebuf[81];
  991.     int page, max_page;
  992.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  993.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  994.     _setbkcolor( (long) screen_bg_color );
  995.     _settextcolor( (short) file_color );
  996.     _clearscreen( _GWINDOW );
  997.     kader();
  998.     show_path();
  999.     show_dir_page( current_page );
  1000.     _setbkcolor( (long) screen_bg_color );
  1001.     _settextcolor( (short) file_color );
  1002.     sprintf(linebuf,"%d/%d",page+1,max_page+1);
  1003.     _settextposition( 1, 72 );
  1004.     outtextm( linebuf );
  1005.     filename( filenumber, CURSOR );  /* emphasize file under cursor */
  1006. }
  1007.  
  1008. /**************************************************************************
  1009.  Cursor movement key handler, page down
  1010. */
  1011. void c_pgdn( int *current_page, int *filenumber)
  1012. {
  1013.    int max_page;
  1014.    max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1015.    if (*current_page<max_page) (*current_page)++;
  1016.     else *current_page=0;
  1017.    show_dir_page( *current_page );
  1018.    *filenumber=((*current_page)*114+1);
  1019.    filename( *filenumber, CURSOR );
  1020. }
  1021.  
  1022. /**************************************************************************
  1023.  Cursor movement key handler, page up
  1024. */
  1025. void c_pgup( int *current_page, int *filenumber)
  1026. {
  1027.     int max_page;
  1028.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1029.     if (*current_page>0) (*current_page)--;
  1030.      else *current_page=max_page;
  1031.     show_dir_page( *current_page );
  1032.     *filenumber=((*current_page)*114+1);
  1033.     filename( *filenumber, CURSOR );
  1034. }
  1035.  
  1036. /**************************************************************************
  1037.  Cursor movement key handler, home
  1038. */
  1039. void c_home( int *current_page, int *filenumber)
  1040. {
  1041.      *current_page=0;
  1042.      show_dir_page( *current_page );
  1043.      *filenumber=((*current_page)*114+1);
  1044.      filename( *filenumber, CURSOR );
  1045. }
  1046.  
  1047. /**************************************************************************
  1048.  Find and display file with starting character chr
  1049. */
  1050. void find_first(char chr, int *current_page, int *filenumber)
  1051. {
  1052.      register int counter;
  1053.      int old_page;
  1054.      int old_filenumber;
  1055.      if (!number_of_files) return;
  1056.      old_page=*current_page;
  1057.      old_filenumber=*filenumber;
  1058.      for (counter=1;counter<number_of_files;counter++) /* should end at last file */
  1059.        if (find[counter].name[0]>=chr) break;
  1060.      *filenumber=counter;
  1061.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  1062.      if (*current_page!=old_page) perform_repaint(*current_page,*filenumber);
  1063.      else
  1064.      {
  1065.     if (*filenumber!=old_filenumber)
  1066.     {
  1067.         filename( old_filenumber, NORMAL );
  1068.         filename( *filenumber, CURSOR );
  1069.     }
  1070.      }
  1071. }
  1072.  
  1073. /**************************************************************************
  1074.  Cursor movement key handler, end
  1075. */
  1076. void c_end( int *current_page, int *filenumber)
  1077. {
  1078.      int max_page;
  1079.      max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1080.      *current_page=max_page;
  1081.      show_dir_page( *current_page );
  1082.      *filenumber=((*current_page)*114+114);
  1083.      *filenumber=(*filenumber<number_of_files) ? *filenumber : number_of_files;
  1084.      filename( *filenumber, CURSOR );
  1085. }
  1086.  
  1087. /**************************************************************************
  1088.  Cursor movement key handler, up arrow
  1089. */
  1090. void c_cup( int *current_page, int *filenumber)
  1091. {
  1092.    int old_filenumber;
  1093.    old_filenumber=*filenumber;
  1094.    if (*filenumber>((*current_page)*114+1)) (*filenumber)--;
  1095.    else
  1096.    {
  1097.     *filenumber=((*current_page)*114+114);
  1098.     *filenumber=(*filenumber<number_of_files) ? *filenumber : number_of_files;
  1099.    }
  1100.    if (*filenumber!=old_filenumber)
  1101.    {
  1102.     filename( old_filenumber, NORMAL );
  1103.     filename( *filenumber, CURSOR );
  1104.    }
  1105. }
  1106.  
  1107. /**************************************************************************
  1108.  Cursor movement key handler, down arrow
  1109. */
  1110. void c_cdn( int *current_page, int *filenumber)
  1111. {
  1112.    int old_filenumber;
  1113.    old_filenumber=*filenumber;
  1114.    if (*filenumber<((*current_page)*114+114) &&
  1115.        *filenumber<number_of_files) (*filenumber)++;
  1116.     else *filenumber=((*current_page)*114+1);
  1117.    filename( old_filenumber, NORMAL );
  1118.    filename( *filenumber, CURSOR );
  1119. }
  1120.  
  1121. /**************************************************************************
  1122.  Cursor movement key handler , right arrow
  1123. */
  1124. void c_cri( int *current_page, int *filenumber)
  1125. {
  1126.     int old_filenumber;
  1127.     old_filenumber=*filenumber;
  1128.     if ((*filenumber <= ((*current_page)*114+95)) &&
  1129.     ((*filenumber+19) <= number_of_files)) (*filenumber)+=19;
  1130.     else
  1131.     {
  1132.     (*filenumber)%=19;
  1133.     if (!(*filenumber)) *filenumber=19;
  1134.     (*filenumber)+=((*current_page)*114);
  1135.     }
  1136.     if (*filenumber!=old_filenumber)
  1137.     {
  1138.     filename( old_filenumber, NORMAL );
  1139.     filename( *filenumber, CURSOR );
  1140.     }
  1141. }
  1142.  
  1143. /**************************************************************************
  1144.  Cursor movement key handler, left arrow
  1145. */
  1146. void c_cle( int *current_page, int *filenumber)
  1147. {
  1148.     int old_filenumber;
  1149.     int maxcolumnnumber;
  1150.     old_filenumber=*filenumber;
  1151.     if (*filenumber>=((*current_page)*114+1)+19) (*filenumber)-=19;
  1152.     else
  1153.     {
  1154.     maxcolumnnumber=5;
  1155.     while ((*filenumber+maxcolumnnumber*19)>number_of_files) maxcolumnnumber--;
  1156.     (*filenumber)+=maxcolumnnumber*19;
  1157.     }
  1158.     if (*filenumber!=old_filenumber)
  1159.     {
  1160.     filename( old_filenumber, NORMAL );
  1161.     filename( *filenumber, CURSOR );
  1162.     }
  1163. }
  1164.  
  1165.  
  1166. /***********************************************************************
  1167.  returns 0 if no key waiting, key code if key waiting
  1168. */
  1169. unsigned int n_kbhit()
  1170. {
  1171.     int kread = _KEYBRD_READ;
  1172.     int kready = _KEYBRD_READY;
  1173.     int kshiftstatus = _KEYBRD_SHIFTSTATUS;
  1174.  
  1175.     /* If bit 4 of the byte at 0x0040:0x0096 is set, the new keyboard
  1176.      * is present.
  1177.      */
  1178.     if( peek( 0x00400096 ) & 0x10 )
  1179.     {
  1180.     kread = _NKEYBRD_READ;
  1181.     kready = _NKEYBRD_READY;
  1182.     kshiftstatus = _NKEYBRD_SHIFTSTATUS;
  1183.     }
  1184.     return _bios_keybrd( kready );
  1185. }
  1186.  
  1187. /************************************************************************
  1188.  Entry point of directory handler
  1189.  Globals: find, files structure
  1190.       number_of_files
  1191.       colors
  1192.  Returns SUCCESS if a valid choice has been made, else EXIT_RESTORE if ESCaped
  1193.  or EXIT_KEEP if Leaved
  1194.  Passes selected file in string selected
  1195. */
  1196. int handle_dir( char *searchstr, char *selected , int safe_mode)
  1197. {
  1198.     int key;
  1199.     int repaint;
  1200.     static int current_page=0;
  1201.     static int filenumber=1;
  1202.     int old_filenumber;
  1203.     short  oldfgd;               /* old foreground color */
  1204.     long   oldbgd;               /* old background color */
  1205.     struct rccoord oldpos;
  1206.     short oldcursor;             /* old cursor shape */
  1207.     int olddrive, lastdrive, tempdrive, newdrive;
  1208.     char oldcwd[_MAX_PATH];
  1209.     static char searchstring[13]={"\0"};
  1210.     int row, col;                       /* mouse variables */
  1211.     int finished;
  1212.     struct videoconfig vc;
  1213.     char scratch[ _MAX_PATH ];          /* scratch string space */
  1214.     int exit_and_keep=FALSE;        /* boolean for 'l' function */
  1215.     char *dummyspace;            /* memory reserved for saveScrn */
  1216.     struct diskfree_t drvinfo;
  1217.     char comspec[_MAX_PATH];
  1218.  
  1219.     strcpy(comspec,getenv("COMSPEC"));
  1220.     if (!strlen(comspec)) strcpy(comspec,"COMMAND"); /* default program to run is COMMAND.COM */
  1221.  
  1222.     /* Save original foreground, background, and text position. */
  1223.     init_mouse();
  1224.     oldfgd = _gettextcolor();
  1225.     oldbgd = _getbkcolor();
  1226.     oldpos = _gettextposition();
  1227.     oldcursor=_gettextcursor();
  1228.     _settextcursor( 0x2000 );
  1229.     _settextwindow( 3, 1, 23, 80 );
  1230.  
  1231.     _getvideoconfig( &vc );
  1232.  
  1233.     if (vc.mode==_TEXTMONO)
  1234.     {
  1235.     screen_bg_color   = M_BLACK_BG;
  1236.     file_color        = M_GRAY;
  1237.     directory_color   = M_WHITE;
  1238.     cursor_bg_color   = M_BLACK_BG;
  1239.     cursor_file_color = M_GRAY_UNDL;
  1240.     cursor_directory_color = M_WHITE_UNDL;
  1241.     info_bg_color     = M_BLACK_BG;
  1242.     info_text_color   = M_WHITE;
  1243.     error_text_color  = M_WHITE;
  1244.     prompt_text_color = M_WHITE;
  1245.         hidden_file_color            = M_GRAY;
  1246.         hidden_directory_color       = M_WHITE;
  1247.     volume_label_color         = M_GRAY;
  1248.         cursor_hidden_file_color     = M_GRAY_UNDL;
  1249.     cursor_hidden_directory_color= M_WHITE_UNDL;
  1250.         cursor_volume_label_color    = M_GRAY_UNDL;
  1251.     }
  1252.  
  1253.     if (!strlen(searchstring)) strcpy(searchstring,searchstr); /* keep old definition */
  1254.     if (!strlen(searchstring)) strcpy(searchstring,"*.*");
  1255.     find=(FIND_T_SMALL *) 0L;
  1256.     if (max_files<=0) max_files=MAX_FILES;
  1257.  
  1258.     dummyspace = (char *) malloc (4096 + 1024);    /* alloceer ruimte voor screen saves + 1k extra voor fff enzo */
  1259.     if( !(find = (FIND_T_SMALL *)calloc( (size_t) max_files + 2, (size_t) sizeof(FIND_T_SMALL) )) )
  1260.     {
  1261.     if (dummyspace) free(dummyspace);
  1262.     _settextwindow( 1, 1, 25, 80 );
  1263.     _settextposition( oldpos.row, oldpos.col );
  1264.     _settextcursor( oldcursor );
  1265.     printf("Cannot allocate memory for %d files",max_files);
  1266.     alert();
  1267.     wait_sec(1000);
  1268.     return FAILURE;
  1269.     }
  1270.     if (dummyspace) free(dummyspace);      /* hoppa, we hebben weer lucht */
  1271.  
  1272.     /* Install our hard error handler. */
  1273.     _harderr( hhandler );
  1274.  
  1275.     /* Save current drive and current working directory. */
  1276.     olddrive = lastdrive = _getdrive();
  1277.     getcwd( oldcwd, _MAX_PATH );
  1278.  
  1279.     repaint=TRUE;
  1280.     extract_directory( searchstring );
  1281.     if (filenumber>number_of_files)     /* can we restore the cursor ? */
  1282.     {
  1283.     current_page=0;         /* no */
  1284.     filenumber=1;
  1285.     }
  1286.     finished=FALSE;
  1287.     do
  1288.     {
  1289.     dos_error=0;
  1290.     dos_retries=0;
  1291.     
  1292.     if (repaint)
  1293.     {
  1294.          /* maak kader repaint */
  1295.          perform_repaint(current_page, filenumber);
  1296.          repaint=FALSE;
  1297.     }
  1298.  
  1299.     if (mouse_present)
  1300.     {
  1301.       switch (read_left_button_queue(&row,&col))
  1302.       {
  1303.         case 0: break;
  1304.         case 1: if (!number_of_files) break;
  1305.             old_filenumber=filenumber;
  1306.             filenumber=(row-4)+(current_page*114+1)+((col-2)/13)*19;
  1307.             if (filenumber>number_of_files) filenumber=old_filenumber;
  1308.             if (filenumber!=old_filenumber)
  1309.             {
  1310.             filename( old_filenumber, NORMAL );
  1311.             filename( filenumber, CURSOR );
  1312.             }
  1313.             break;
  1314.         case 2: if (!number_of_files) break;
  1315.             old_filenumber=filenumber;
  1316.             filenumber=(row-4)+(current_page*114+1)+((col-2)/13)*19;
  1317.             if (filenumber<=number_of_files)
  1318.             {
  1319.             if (filename( filenumber, NOREPAINT )=='D')
  1320.             {
  1321.                repaint=TRUE;
  1322.                if (!strcmp(find[filenumber].name,"..")) /* going up */
  1323.                {
  1324.                    find_parent( ¤t_page, &filenumber, searchstring);
  1325.                }
  1326.                else  /* going down */
  1327.                {
  1328.                 chdir( find[filenumber].name );
  1329.                 extract_directory( searchstring );
  1330.                 current_page=0;
  1331.                 filenumber=1;
  1332.                }
  1333.             } else finished=TRUE; /* add normal file handling here */
  1334.             } else filenumber=old_filenumber;
  1335.             break;
  1336.       }
  1337.       if (read_right_button_queue(&row,&col) && number_of_files) /* right button */
  1338.       {
  1339.         _getdcwd( _getdrive(), scratch, _MAX_PATH );
  1340.         if (strlen(scratch)>3)
  1341.         {
  1342.            repaint=TRUE;
  1343.            find_parent( ¤t_page, &filenumber,searchstring);
  1344.         }
  1345.       }
  1346.     }
  1347.  
  1348.        if (n_kbhit() && !finished)
  1349.        {
  1350.     key = getkey();
  1351.     if (key<256) key = tolower(key);
  1352.     if (key=='l' && !safe_mode)    /* leave FS here */
  1353.     {
  1354.          exit_and_keep=TRUE;
  1355.          key=ESC;
  1356.     }
  1357.     if (key==ESC) break;     /* ESC, exit do while TRUE loop */
  1358.     repaint=FALSE;
  1359.     switch (key)
  1360.     {
  1361.         case 'i': if (number_of_files) fileinfo( filenumber );
  1362.               break;
  1363.         case 'h':
  1364.         case '?': helpscreen();
  1365.               break;
  1366.         case 'p': aboutscreen();
  1367.               break;
  1368.         case 'a': if (safe_mode) break;
  1369.               if (number_of_files)
  1370.               switch (ed_attributes(filenumber))
  1371.               {
  1372.               case FAILURE: show_error("Cannot change the attributes ");
  1373.                     break;
  1374.               case SUCCESS: repaint=TRUE;
  1375.                     extract_directory( searchstring );
  1376.                     if (filenumber > number_of_files)
  1377.                     {
  1378.                         filenumber=1;
  1379.                         current_page=0;
  1380.                     }
  1381.                     break;
  1382.               case NOCHANGE: break;
  1383.               }
  1384.               break;
  1385.         case K_PGDN: if (number_of_files) c_pgdn( ¤t_page, &filenumber);
  1386.              break;
  1387.         case K_PGUP: if (number_of_files) c_pgup( ¤t_page, &filenumber);
  1388.              break;
  1389.         case K_HOME: if (number_of_files) c_home( ¤t_page, &filenumber);
  1390.              break;
  1391.         case K_END: if (number_of_files) c_end( ¤t_page, &filenumber);
  1392.             break;
  1393.         case K_CUP: if (number_of_files) c_cup( ¤t_page, &filenumber);
  1394.             break;
  1395.         case K_CDN: if (number_of_files) c_cdn( ¤t_page, &filenumber);
  1396.             break;
  1397.         case K_CRI: if (number_of_files) c_cri( ¤t_page, &filenumber);
  1398.             break;
  1399.         case K_CLE: if (number_of_files) c_cle( ¤t_page, &filenumber);
  1400.             break;
  1401.         case '\r': if (!number_of_files) break;
  1402.                repaint=TRUE;
  1403.                if (filename( filenumber, NOREPAINT )=='D')
  1404.                {
  1405.                if (!strcmp(find[filenumber].name,"..")) /* going up */
  1406.                {
  1407.                    find_parent( ¤t_page, &filenumber,searchstring);
  1408.                }
  1409.                else  /* going down */
  1410.                {
  1411.                    chdir( find[filenumber].name );
  1412.                    extract_directory( searchstring );
  1413.                    current_page=0;
  1414.                    filenumber=1;
  1415.                }
  1416.                } else finished=TRUE; /* add normal file handling here */
  1417.                break;
  1418.         case 'u':  if (!number_of_files) break;
  1419.                _getdcwd( _getdrive(), scratch, _MAX_PATH );
  1420.                if (strlen(scratch)>3)
  1421.                {
  1422.                repaint=TRUE;
  1423.                find_parent( ¤t_page, &filenumber,searchstring);
  1424.                }
  1425.                break;
  1426.         case 't': if (!number_of_files) break;
  1427.               _getdcwd( _getdrive(), scratch, _MAX_PATH );
  1428.               if (strlen(scratch)>3)
  1429.               {
  1430.               repaint=TRUE;
  1431.               scratch[0]= (char) (_getdrive() - 1 + 'A');
  1432.               scratch[1]=':';
  1433.               scratch[2]='\\';
  1434.               scratch[3]='\0';
  1435.               chdir( scratch );
  1436.               extract_directory( searchstring );
  1437.               current_page=0;
  1438.               filenumber=1;
  1439.               }
  1440.               break;
  1441.         case 'x': if (safe_mode) break;
  1442.               hide_mouse();
  1443.               _settextcolor( oldfgd );
  1444.               _setbkcolor( oldbgd );
  1445.               _clearscreen( _GCLEARSCREEN );
  1446.               _settextcursor( oldcursor );
  1447.               lastdrive = _getdrive();
  1448.               strcpy(scratch,"PROMPT=Type EXIT to return to FS$_$p$g");
  1449.               putenv(scratch);
  1450.               if (!_swap) xsystem(comspec);
  1451.               else system(comspec);
  1452.               _harderr( hhandler );
  1453.               init_mouse();
  1454.               _settextcursor( 0x2000 );
  1455.               _chdrive( lastdrive );
  1456.               extract_directory( searchstring );
  1457.               if (filenumber>number_of_files)   /* can we restore the cursor ? */
  1458.               {
  1459.               current_page=0;
  1460.               filenumber=1;
  1461.               }
  1462.               repaint=TRUE;
  1463.               break;
  1464.  
  1465.         case 'f': if (freespace( scratch )==SUCCESS)
  1466.              {
  1467.                _settextposition( 23, 26 );
  1468.                _settextcolor( (short) prompt_text_color );
  1469.                outtextm( scratch );
  1470.                while (!n_kbhit() && !mouse_button_pressed()) /* wait */ ;
  1471.                _settextposition( 23, 26 );
  1472.                _settextcolor( (short) file_color );
  1473.                outtextm("══════════════════════════════");
  1474.              }
  1475.              break;
  1476.         case 'd': newdrive=ask_drive_number(" Type new drive letter or ESC ");
  1477.               if (newdrive!=-1)
  1478.               {
  1479.             dos_error=0;
  1480.             dos_retries=0;
  1481.             lastdrive = tempdrive = _getdrive();      /* start excessive error checking to prevent */
  1482.             if (_chdrive( newdrive))           /* triggering the dos error handler */
  1483.             {
  1484.                 show_error("No such drive ");    /* first check */
  1485.                 _chdrive( lastdrive );
  1486.             } else lastdrive= newdrive;
  1487.  
  1488.             dos_error=0;
  1489.             dos_retries=0;
  1490.             do
  1491.             {
  1492.                if (!drvalid(lastdrive-1) || dos_error) /* second check */
  1493.                {
  1494.                    dos_error=0;
  1495.                    dos_retries=0;
  1496.                    show_error("Cannot select this drive ");
  1497.                    lastdrive=tempdrive;
  1498.                    newdrive=ask_drive_number(" Enter a valid drive letter or ESC ");          /* ask for a valid drive */
  1499.                    if (newdrive!=-1) lastdrive=newdrive;  /* try this one or go back to the initial drive (tempdrive) */
  1500.                    _chdrive( lastdrive ); /* force to a valid drive */
  1501.                }
  1502.                else
  1503.                {
  1504.                    _dos_getdiskfree( lastdrive, &drvinfo ); /* third check, try to access the disk */
  1505.                    if (dos_error)
  1506.                    {
  1507.                    dos_error=0;
  1508.                    dos_retries=0;
  1509.                    show_error("Cannot select this drive ");
  1510.                    lastdrive=tempdrive;
  1511.                    newdrive=ask_drive_number(" Enter a valid drive letter or ESC ");          /* ask for a valid drive */
  1512.                    if (newdrive!=-1) lastdrive=newdrive;    /* try this one or go back to the initial drive (tempdrive) */
  1513.                    _chdrive( lastdrive ); /* force to a valid drive */
  1514.                    }
  1515.                }
  1516.             } while (dos_error);
  1517.             extract_directory( searchstring );
  1518.             current_page=0;
  1519.             filenumber=1;
  1520.             repaint=TRUE;
  1521.               }
  1522.               else
  1523.               {
  1524.                _settextposition( 23, 25 );
  1525.                outtextm("══════════════════════════════");
  1526.               }
  1527.               break;
  1528.         case K_DEL: if (safe_mode) break;
  1529.             if (!number_of_files) break;
  1530.             if (!strcmp(find[filenumber].name,"..")) break;  /* this could give you a lot of free space */
  1531.             _settextposition( 23, 17 );
  1532.             _settextcolor( (short) prompt_text_color );
  1533.             outtextm(" Type Y to delete or any other key to cancel ");
  1534.             _settextcolor( (short) file_color );
  1535.             _settextposition( 1, 1 );        /* prevent scroll-up from dos error */
  1536.             key = getkey();
  1537.             if (key=='y' || key=='Y')
  1538.             {
  1539.                if (filename( filenumber, NOREPAINT )=='D')
  1540.                {
  1541.                 if (rmdir(find[filenumber].name)) /* first try normal delete, will fail if not empty */
  1542.                 {                  /* then try to clean up */
  1543.                        _settextposition( 23, 4 );
  1544.                        _settextcolor( (short) prompt_text_color );
  1545.                        outtextm(" Directory contains files. Type Y to delete all or any other key to cancel ");
  1546.                        _settextcolor( (short) file_color );
  1547.                        _settextposition( 1, 1 );      /* prevent scroll-up from dos error */
  1548.                        key = getkey();
  1549.                        if (key=='y' || key=='Y')
  1550.                        {
  1551.                        do_dir(find[filenumber].name);
  1552.                        }
  1553.                 }
  1554.                }
  1555.                else
  1556.                {
  1557.                 if (filename( filenumber, NOREPAINT )=='V')
  1558.                 {
  1559.                     if (FilDelVolid( (unsigned char) _getdrive() )==NODEL)
  1560.                        show_error("Cannot delete this volume label ");
  1561.                 }
  1562.                 else
  1563.                 {
  1564.                     if (unlink(find[filenumber].name))
  1565.                        show_error("Cannot delete this file ");
  1566.                 }
  1567.                }
  1568.                extract_directory( searchstring );
  1569.                if (filenumber > number_of_files)
  1570.                {
  1571.                    filenumber=1;
  1572.                    current_page=0;
  1573.                }
  1574.                repaint=TRUE;
  1575.             } else
  1576.             {
  1577.                _settextposition( 23, 17 );
  1578.                _settextcolor( (short) file_color );
  1579.                outtextm("═════════════════════════════════════════════");
  1580.             }
  1581.             break;
  1582.         case '/': repaint=TRUE;
  1583.               extract_directory( searchstring );
  1584.               if (filenumber > number_of_files)
  1585.               {
  1586.               filenumber=1;
  1587.               current_page=0;
  1588.               }
  1589.               break;
  1590.         case 'v': if (safe_mode) break;
  1591.               switch (rename_volume_label(0)) /* use dummy zero index */
  1592.               {
  1593.                   case FAILURE: show_error("Cannot create this volume label ");
  1594.                         break;
  1595.                   case SUCCESS: repaint=TRUE;
  1596.                         extract_directory( searchstring );
  1597.                         if (filenumber > number_of_files)
  1598.                         {
  1599.                         filenumber=1;
  1600.                         current_page=0;
  1601.                         }
  1602.                         break;
  1603.                   case NOCHANGE: break;
  1604.                       }
  1605.               break;
  1606.         case 's': hide_mouse();
  1607.               if (number_of_files)
  1608.              if (show_file( find[filenumber].name)==SUCCESS)
  1609.                 repaint=TRUE;
  1610.               show_mouse();
  1611.               break;
  1612.         case 'e': if (safe_mode) break;
  1613.               if (!number_of_files) break;
  1614.               hide_mouse();
  1615.               repaint=TRUE;
  1616.               _settextcolor( oldfgd );
  1617.               _setbkcolor( oldbgd );
  1618.               _settextcursor( oldcursor );
  1619.               lastdrive = _getdrive();
  1620.               if (!_swap) xsystem(find[filenumber].name);
  1621.               else system(find[filenumber].name);
  1622.               _settextcolor( (short) prompt_text_color );
  1623.               _setbkcolor( (long) screen_bg_color );
  1624.               _settextposition( 23, 25 );
  1625.               outtextm(" Press any key to continue ");
  1626.               getkey();
  1627.               _harderr( hhandler );
  1628.               init_mouse();
  1629.               _settextcursor( 0x2000 );
  1630.               extract_directory( searchstring );
  1631.               if (filenumber>number_of_files)   /* can we restore the cursor ? */
  1632.               {
  1633.               current_page=0;
  1634.               filenumber=1;
  1635.               }
  1636.               break;
  1637.         case 'm': strcpy(scratch,searchstring);
  1638.               if (edit("Enter a filename mask, ESC to cancel",searchstring, 12,":\\ +=[];|,<>/\""))
  1639.               {
  1640.              if (strcmp(searchstring,scratch))
  1641.              {
  1642.                extract_directory( searchstring );
  1643.                if (filenumber>number_of_files)      /* can we restore the cursor ? */
  1644.                {
  1645.                    current_page=0;
  1646.                    filenumber=1;
  1647.                }
  1648.                repaint=TRUE;
  1649.              }
  1650.               }
  1651.               break;
  1652.         case 'r': if (safe_mode) break;
  1653.               if (number_of_files)
  1654.               {
  1655.             if (filename( filenumber, NOREPAINT )=='V')
  1656.             {
  1657.                 switch (rename_volume_label(filenumber))
  1658.                 {
  1659.                   case FAILURE: show_error("Cannot rename this volume label ");
  1660.                         break;
  1661.                   case SUCCESS: repaint=TRUE;
  1662.                         extract_directory( searchstring );
  1663.                         if (filenumber > number_of_files)
  1664.                         {
  1665.                         filenumber=1;
  1666.                         current_page=0;
  1667.                         }
  1668.                         break;
  1669.                   case NOCHANGE: break;
  1670.                 }
  1671.             }
  1672.             else switch (rename_file(filenumber))  /* file or dir */
  1673.             {
  1674.               case FAILURE: show_error("Cannot rename this file ");
  1675.                     break;
  1676.               case SUCCESS: repaint=TRUE;
  1677.                     extract_directory( searchstring );
  1678.                     if (filenumber > number_of_files)
  1679.                     {
  1680.                         filenumber=1;
  1681.                         current_page=0;
  1682.                     }
  1683.                     break;
  1684.               case NOCHANGE: break;
  1685.             }
  1686.               }
  1687.               break;
  1688.         case 'n': if (safe_mode) break;
  1689.               switch (make_directory())
  1690.               {
  1691.               case FAILURE: show_error("Cannot create this directory ");
  1692.                     break;
  1693.               case SUCCESS: repaint=TRUE;
  1694.                     extract_directory( searchstring );
  1695.                     if (filenumber > number_of_files)
  1696.                     {
  1697.                         filenumber=1;
  1698.                         current_page=0;
  1699.                     }
  1700.                     break;
  1701.               case NOCHANGE: break;
  1702.               }
  1703.               break;
  1704.         case 'w': switch (whereis(searchstring, ¤t_page, &filenumber))
  1705.               {
  1706.               case U_SELECT: finished=TRUE;
  1707.                      break;
  1708.               case U_GOTO: repaint=TRUE;
  1709.                        break;
  1710.               case FAILURE: repaint=TRUE;
  1711.                     show_error( "File find failed ");
  1712.                     extract_directory( searchstring );
  1713.                     if (filenumber > number_of_files)
  1714.                     {
  1715.                          filenumber=1;
  1716.                          current_page=0;
  1717.                     }
  1718.                     break;
  1719.               case U_ESC: break;
  1720.               }
  1721.               break;
  1722.         case 'c': if (safe_mode) break;
  1723.               if (number_of_files)
  1724.               switch (copy_file(filenumber))
  1725.               {
  1726.              case FAILURE: show_error("Cannot copy this file ");
  1727.                        break;
  1728.              case SUCCESS: repaint=TRUE;
  1729.                        extract_directory( searchstring );
  1730.                        if (filenumber > number_of_files)
  1731.                        {
  1732.                      filenumber=1;
  1733.                      current_page=0;
  1734.                        }
  1735.                        break;
  1736.              case NOCHANGE: break;
  1737.               }
  1738.               break;
  1739.         case SCAN_A: find_first('A',¤t_page, &filenumber);
  1740.              break;
  1741.         case SCAN_B: find_first('B',¤t_page, &filenumber);
  1742.              break;
  1743.         case SCAN_C: find_first('C',¤t_page, &filenumber);
  1744.              break;
  1745.         case SCAN_D: find_first('D',¤t_page, &filenumber);
  1746.              break;
  1747.         case SCAN_E: find_first('E',¤t_page, &filenumber);
  1748.              break;
  1749.         case SCAN_F: find_first('F',¤t_page, &filenumber);
  1750.              break;
  1751.         case SCAN_G: find_first('G',¤t_page, &filenumber);
  1752.              break;
  1753.         case SCAN_H: find_first('H',¤t_page, &filenumber);
  1754.              break;
  1755.         case SCAN_I: find_first('I',¤t_page, &filenumber);
  1756.              break;
  1757.         case SCAN_J: find_first('J',¤t_page, &filenumber);
  1758.              break;
  1759.         case SCAN_K: find_first('K',¤t_page, &filenumber);
  1760.              break;
  1761.         case SCAN_L: find_first('L',¤t_page, &filenumber);
  1762.              break;
  1763.         case SCAN_M: find_first('M',¤t_page, &filenumber);
  1764.              break;
  1765.         case SCAN_N: find_first('N',¤t_page, &filenumber);
  1766.              break;
  1767.         case SCAN_O: find_first('O',¤t_page, &filenumber);
  1768.              break;
  1769.         case SCAN_P: find_first('P',¤t_page, &filenumber);
  1770.              break;
  1771.         case SCAN_Q: find_first('Q',¤t_page, &filenumber);
  1772.              break;
  1773.         case SCAN_R: find_first('R',¤t_page, &filenumber);
  1774.              break;
  1775.         case SCAN_S: find_first('S',¤t_page, &filenumber);
  1776.              break;
  1777.         case SCAN_T: find_first('T',¤t_page, &filenumber);
  1778.              break;
  1779.         case SCAN_U: find_first('U',¤t_page, &filenumber);
  1780.              break;
  1781.         case SCAN_V: find_first('V',¤t_page, &filenumber);
  1782.              break;
  1783.         case SCAN_W: find_first('W',¤t_page, &filenumber);
  1784.              break;
  1785.         case SCAN_X: find_first('X',¤t_page, &filenumber);
  1786.              break;
  1787.         case SCAN_Y: find_first('Y',¤t_page, &filenumber);
  1788.              break;
  1789.         case SCAN_Z: find_first('Z',¤t_page, &filenumber);
  1790.              break;
  1791.  
  1792.         case '!': sprintf(scratch,"Memory free: %u ", _memmax()); /* debug info */
  1793.               show_error( scratch );
  1794.               break;
  1795.         default: break;
  1796.     } /* switch */
  1797.        } /* kbhit */
  1798.     } while (!finished);
  1799.  
  1800.     if (key!=ESC || finished)   /* do not miss the mouse selection */
  1801.     {
  1802.     /* construct filename */
  1803.     lastdrive = _getdrive();
  1804.     _getdcwd( lastdrive, selected, _MAX_PATH );
  1805.     if (selected[strlen(selected)-1]!='\\') strcat(selected,"\\");
  1806.  
  1807.     strcat(selected,find[filenumber].name);
  1808.     }
  1809.  
  1810.     if (!exit_and_keep)     /* restore old situation */
  1811.     {
  1812.        _chdrive( olddrive );
  1813.        chdir( oldcwd );
  1814.     }
  1815.     hide_mouse();
  1816.     /* Restore original foreground and background. */
  1817.     _settextcolor( oldfgd );
  1818.     _setbkcolor( oldbgd );
  1819.     _clearscreen( _GWINDOW );
  1820.     _settextwindow( 1, 1, 25, 80 );
  1821.     _settextposition( oldpos.row, oldpos.col );
  1822.     _settextcursor( oldcursor );
  1823.     if (find) free( find );
  1824.     if (key==ESC && !finished)
  1825.     {
  1826.     if (exit_and_keep) return EXIT_KEEP;
  1827.     else return EXIT_RESTORE;
  1828.     }
  1829.     else return SUCCESS;
  1830. } /* end handle_dir */
  1831.  
  1832. /****************************************************************************
  1833.  renames file
  1834. */
  1835. int rename_file( int filenumber)
  1836. {
  1837.     char newname[50];
  1838.     strcpy(newname,find[filenumber].name);
  1839.     if (edit("Rename: Enter a new filename, ESC to cancel",newname,48," +=[];|,<>/?*\""))
  1840.     {
  1841.     if (!strlen(newname)) return NOCHANGE;         /* null filename */
  1842.     if (!valid_filename(newname)) return FAILURE;  /* invalid filename */
  1843.     if (strcmp(find[filenumber].name,newname))
  1844.        if (rename(find[filenumber].name,newname)) return FAILURE;
  1845.        else return SUCCESS;                        /* rename succeeded */
  1846.     }
  1847.     return NOCHANGE;                       /* ESCaped */
  1848. }
  1849.  
  1850. /****************************************************************************
  1851.  renames volume_label
  1852. */
  1853. int rename_volume_label( int filenumber)
  1854. {
  1855.     char newname[50];
  1856.     char *p;
  1857.  
  1858.     strcpy(newname,find[filenumber].name);
  1859.     if (p=strrchr(newname,'.')) memmove( p, p+1, strlen(p+1)+1); /* remove . */
  1860.  
  1861.  
  1862.     if (edit("Enter a new volume label, ESC to cancel",newname,11,"+=[];|,.<>/?*\\:()&^\""))
  1863.     {
  1864.     if (!strlen(newname)) return NOCHANGE;           /* null filename */
  1865.     strupr(newname);
  1866.     if (strcmp(find[filenumber].name,newname))
  1867.        if (FilSetVolid( (unsigned char) _getdrive() ,newname)!=NOERROR) return FAILURE;
  1868.        else return SUCCESS;                        /* rename succeeded */
  1869.     }
  1870.     return NOCHANGE;                       /* ESCaped */
  1871. }
  1872.  
  1873. /*************************************************************************
  1874.  Change file attributes
  1875. */
  1876. int ed_attributes( int filenumber)
  1877. {
  1878.     char attrbuf[5];
  1879.     unsigned int fattr;
  1880.     strcpy( attrbuf, "");
  1881.     if (find[filenumber].attrib & _A_RDONLY) strcat(attrbuf,"R");
  1882.     if (find[filenumber].attrib & _A_HIDDEN) strcat(attrbuf,"H");
  1883.     if (find[filenumber].attrib & _A_SYSTEM) strcat(attrbuf,"S");
  1884.     if (find[filenumber].attrib & _A_ARCH)   strcat(attrbuf,"A");
  1885.  
  1886.     if (edit("(R)eadonly, (H)idden, (S)ystem, (A)rchive",attrbuf,4,
  1887.     " !@#$%^&*()+-_=[]{};:'\"\\|`~,<.>/?1234567890BCEDFGIJKLMNOPQTUVWXYZbcdefgijklmnopqtuvwxyz"))
  1888.     {
  1889.     fattr=0;
  1890.     strlwr(attrbuf);
  1891.     if (strchr(attrbuf, 'r')) fattr|=_A_RDONLY;
  1892.     if (strchr(attrbuf, 'h')) fattr|=_A_HIDDEN;
  1893.     if (strchr(attrbuf, 's')) fattr|=_A_SYSTEM;
  1894.     if (strchr(attrbuf, 'a')) fattr|=_A_ARCH;
  1895.     if ((find[filenumber].attrib & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH)) != (char) fattr)
  1896.        if (_dos_setfileattr( find[filenumber].name, fattr)) return FAILURE;
  1897.        else return SUCCESS;
  1898.     }
  1899.     return NOCHANGE;
  1900. }
  1901.  
  1902. /***************************************************************************
  1903.  Copy file
  1904. */
  1905. int copy_file( int filenumber)
  1906. {
  1907.     char newname[50];
  1908.     strcpy(newname,find[filenumber].name);
  1909.     if (edit("Copy: Enter a new filename, ESC to cancel",newname,48," +=[];|,<>/?*\""))
  1910.     {
  1911.     if (!strlen(newname)) return NOCHANGE;
  1912.     if (!valid_filename(newname)) return FAILURE;
  1913.     if (strcmp(find[filenumber].name,newname))
  1914.        if (copy(find[filenumber].name,newname)) return FAILURE;
  1915.        else return SUCCESS;
  1916.  
  1917.     }
  1918.     return NOCHANGE;
  1919. }
  1920.  
  1921. /**************************************************************************
  1922.  mkdir
  1923. */
  1924. int make_directory( void )
  1925. {
  1926.     char newname[14];
  1927.     strcpy(newname,"");
  1928.     if (edit("Create: Enter a new directory name, ESC to cancel",newname,12," +=[];|,<>/?*\""))
  1929.     {
  1930.     if (!strlen(newname)) return NOCHANGE;
  1931.     if (!valid_filename(newname)) return FAILURE;
  1932.     if (mkdir(newname)) return FAILURE;
  1933.        else return SUCCESS;
  1934.     }
  1935.     return NOCHANGE;
  1936. }
  1937.  
  1938. /**********************************************************************
  1939.  * Copies one file to another (both specified by path). Dynamically
  1940.  * allocates memory for the file buffer. Prompts before overwriting
  1941.  * existing file. Returns 0 if successful, otherwise an error number.
  1942.  */
  1943. int copy( char *source, char *target )
  1944. {
  1945.     char *buf;
  1946.     int hsource, htarget, ch;
  1947.     unsigned count = 0xff00;
  1948.  
  1949.     /* Open source file and create target, overwriting if necessary. */
  1950.     if( (hsource = open( source, O_BINARY | O_RDONLY )) == - 1 )
  1951.     return errno;
  1952.     htarget = open( target, O_BINARY | O_WRONLY | O_CREAT | O_EXCL,
  1953.                 S_IREAD | S_IWRITE );
  1954.     if( errno == EEXIST )
  1955.     {
  1956.     _settextposition( 23, 25 );
  1957.     _settextcolor( (short) prompt_text_color );
  1958.     outtextm(" Target exists. Overwrite ? ");
  1959.     _settextcolor( (short) file_color );
  1960.     _settextposition( 1, 1 );        /* prevent scroll-up from dos error */
  1961.     ch = getkey();
  1962.     if (ch=='y' || ch=='Y')
  1963.         htarget = open( target, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC,
  1964.                     S_IREAD | S_IWRITE );
  1965.     }
  1966.     if( htarget == -1 )
  1967.     return errno;
  1968.  
  1969.     if( filelength( hsource ) < (long) count )
  1970.     count = (int)filelength( hsource );
  1971.  
  1972.     /* Dynamically allocate a large file buffer. If there's not enough
  1973.      * memory for it, find the largest amount available on the near heap
  1974.      * and allocate that. This can't fail, no matter what the memory model.
  1975.      */
  1976.     if( (buf = (char *)malloc( (size_t)count )) == NULL )
  1977.     {
  1978.     count = _memmax();
  1979.     if( (buf = (char *)malloc( (size_t)count )) == NULL )
  1980.     {
  1981.         show_error("Cannot allocate memory for copy");
  1982.         return ENOMEM;
  1983.     }
  1984.     }
  1985.  
  1986.     /* Read-write until there's nothing left. */
  1987.     while( !eof( hsource ) )
  1988.     {
  1989.     /* Read and write input. */
  1990.     if( (count = read( hsource, buf, count )) == -1 )
  1991.         return errno;
  1992.     if( (count = write( htarget, buf, count )) == - 1 )
  1993.         return errno;
  1994.     }
  1995.     /* Close files and release memory. */
  1996.     close( hsource );
  1997.     close( htarget );
  1998.     free( buf );
  1999.     return 0;
  2000. }
  2001.  
  2002. /**************************************************************************
  2003.  display file contents page by page on screen
  2004. */
  2005. int show_file(char *filename)
  2006. {
  2007.     FILE *stream;
  2008.     int key;
  2009.     int line;
  2010.     char buf[85];
  2011.     if ((stream=fopen(filename,"rt")) == NULL )
  2012.     {
  2013.     show_error("Cannot show this file ");
  2014.     return FAILURE;
  2015.     }
  2016.     _settextcolor( (short) file_color );
  2017.     _setbkcolor( (long) screen_bg_color );
  2018.     _clearscreen( _GWINDOW );
  2019.     _settextposition( 1, 1 );
  2020.     line=0;
  2021.     while (fgets( buf, 80, stream ))
  2022.     {
  2023.     line++;
  2024.     _outtext(buf);
  2025.     if (line==20)
  2026.     {
  2027.        line=0;
  2028.        _settextcolor( (short) prompt_text_color );
  2029.        _outtext("*** Press Esc to cancel, any other key to continue ***");
  2030.        _settextcolor( (short) file_color );
  2031.        if ((key=getkey())==ESC) break;
  2032.        _outtext("\n");
  2033.     }
  2034.     }
  2035.     if (key!=ESC)
  2036.     {
  2037.     _settextcolor( (short) prompt_text_color );
  2038.     _outtext("\n*** Press any key to continue ***");
  2039.     getkey();
  2040.     }
  2041.     fclose(stream);
  2042.     _settextcolor( (short) file_color );
  2043.     return SUCCESS;
  2044. }
  2045.  
  2046. /***************************************************************************
  2047.  Displays common edit screen
  2048.  Returns FALSE if ESCaped
  2049. */
  2050. int edit(char *title, char *string, int length , char *illegal)
  2051. {
  2052.     char scratch[_MAX_PATH];
  2053.     short x,y;
  2054.     char b[(5*53)+10]={                /* Buffer for string */
  2055.                "╔══════════════════════════════════════════════════╗\n"
  2056.                "║                                                  ║\n"
  2057.                "╟──────────────────────────────────────────────────╢\n"
  2058.                "║                                                  ║\n"
  2059.                "╚══════════════════════════════════════════════════╝\n"
  2060.               };
  2061.     int result;
  2062.     char *savedscreen;
  2063.  
  2064.     strcpy(scratch,string);
  2065.  
  2066.     savedscreen=saveScrn();
  2067.  
  2068.     y = ((25 - 5) / 2) + 1;     /* 5 lines */
  2069.     x =  (80 - 52) / 2;         /* 52 visible characters per line */
  2070.  
  2071.     _settextcolor( (short) info_text_color );
  2072.     _setbkcolor( (long) info_bg_color );
  2073.  
  2074.     /* Use text window to place output in middle of screen. */
  2075.     _settextwindow( y, x, y + 5, x + 52 );
  2076.     shadebox( y, x, y + 5 - 1, x + 52 - 1 );
  2077.     outtextm( b );
  2078.     _settextposition( 2, 3 );
  2079.     outtextm(title);
  2080.     if (editstring(4, 3, scratch, illegal , length))
  2081.     {
  2082.        strcpy(string,scratch);
  2083.        result=TRUE;
  2084.     }
  2085.     else result=FALSE;
  2086.  
  2087.     _settextwindow( 3, 1, 23, 80 );
  2088.     _setbkcolor( (long) screen_bg_color );
  2089.     savedscreen=restScrn(savedscreen);
  2090.     return result;
  2091. }
  2092.  
  2093. /**************************************************************************
  2094.  Converting from TC style
  2095. */
  2096. void movmem(void *src, void *dest, unsigned length)
  2097. {
  2098.      memmove(dest, src, length);
  2099. }
  2100.  
  2101. /***************************************************************************
  2102.  Returns ASCII or scancode + 256 if no ASCII
  2103. */
  2104. int getkey(void)
  2105. {
  2106.     int kread = _KEYBRD_READ;
  2107.     int kready = _KEYBRD_READY;
  2108.     int kshiftstatus = _KEYBRD_SHIFTSTATUS;
  2109.     unsigned key;
  2110.     int lo, hi;
  2111.     /* If bit 4 of the byte at 0x0040:0x0096 is set, the new keyboard
  2112.      * is present.
  2113.      */
  2114.     if( peek( 0x00400096 ) & 0x10 )
  2115.     {
  2116.     kread = _NKEYBRD_READ;
  2117.     kready = _NKEYBRD_READY;
  2118.     kshiftstatus = _NKEYBRD_SHIFTSTATUS;
  2119.     }
  2120.     key=_bios_keybrd( kread );
  2121.     lo = key & 0X00FF;
  2122.     hi = (key & 0XFF00) >> 8;
  2123.     return((lo == 0 || lo == 0xE0 ) ? hi + 256 : lo);
  2124. }
  2125.  
  2126. /****************************************************************************
  2127.  Changes the text cursor shape based on the current insert mode
  2128. */
  2129. void changecursor(int insmode)
  2130. {
  2131.  if (insmode)
  2132.   setcursor( 0x090C);
  2133.  else setcursor(0x0A0C);
  2134. } /* changecursor */
  2135.  
  2136. /***************************************************************************
  2137.  Sets the shape of the text cursor
  2138. */
  2139. void setcursor(unsigned int shape)
  2140. {
  2141.  union REGS reg;
  2142.  
  2143.  reg.h.ah = 1;
  2144.  reg.x.cx = shape;
  2145.  int86(0X10, ®, ®);
  2146. } /* setcursor */
  2147.  
  2148. /****************************************************************************
  2149.  Allows the user to edit a string with only certain characters allowed -
  2150.  Returns TRUE if ESC was not pressed, FALSE is ESC was pressed.
  2151. */
  2152. int editstring(int row, int col, char *s, char *illegal, int maxlength)
  2153. {
  2154.  int c, len = strlen(s), pos = len;
  2155.  static int insert=TRUE;
  2156.  register int tel;
  2157.  int mouse_row, mouse_col;
  2158.  int ulc_row, ulc_col, dummy;          /* upper left corner row and column of window */
  2159.  int update=TRUE;
  2160.  changecursor(insert);
  2161.  _gettextwindow(&ulc_row,&ulc_col,&dummy,&dummy);  /* mouse coordinates are absolute! */
  2162.  
  2163.  do
  2164.  {
  2165.   if (update)
  2166.   {
  2167.      _settextposition( row, col );
  2168.      hide_mouse();
  2169.      _outtext(s);
  2170.      for (tel=len;tel<=maxlength;tel++) _outtext(" ");
  2171.      show_mouse();
  2172.      _settextposition( row, col + pos );
  2173.      update=FALSE;
  2174.   }
  2175.  
  2176.   if (mouse_present)
  2177.      if (read_left_button_queue(&mouse_row,&mouse_col))
  2178.      {
  2179.     if (((mouse_row-ulc_row+1)==row) &&
  2180.         ((mouse_col-ulc_col+1)<=(col+len)) &&
  2181.         ((mouse_col-ulc_col+1)>=col))
  2182.     {
  2183.        pos=(mouse_col-ulc_col+1)-col;
  2184.        update=TRUE;
  2185.     }  else alert();
  2186.       }
  2187.  
  2188.   if (n_kbhit())
  2189.   {
  2190.   update=TRUE;
  2191.   switch(c = getkey())
  2192.   {
  2193.    case K_HOME:
  2194.     pos = 0;
  2195.     break;
  2196.    case K_END:
  2197.     pos = len;
  2198.     break;
  2199.    case K_INS:
  2200.     insert = !insert;
  2201.     changecursor(insert);
  2202.     break;
  2203.    case K_CLE:
  2204.     if (pos > 0)
  2205.      pos--;
  2206.     break;
  2207.    case K_CRI:
  2208.     if (pos < len)
  2209.      pos++;
  2210.     break;
  2211.    case BS :
  2212.     if (pos > 0)
  2213.     {
  2214.      movmem(&s[pos], &s[pos - 1], len - pos + 1);
  2215.      pos--;
  2216.      len--;
  2217.     }
  2218.     break;
  2219.    case K_DEL:
  2220.     if (pos < len)
  2221.     {
  2222.      movmem(&s[pos + 1], &s[pos], len - pos);
  2223.      len--;
  2224.     }
  2225.     break;
  2226.    case CR :
  2227.     break;
  2228.    case ESC :
  2229.     len = 0;
  2230.     break;
  2231.    default :
  2232.     if (((illegal[0] == 0) || (strchr(illegal, c) == NULL)) &&
  2233.     ((c >= ' ') && (c <= '~')))
  2234.     {
  2235.      if (insert && len < maxlength)
  2236.      {
  2237.       memmove(&s[pos + 1], &s[pos], len - pos + 1);
  2238.       len++;
  2239.       s[pos++] = (char) c;
  2240.      }
  2241.      if (!insert && pos < maxlength)
  2242.      {
  2243.      if ((pos >= len) && (len < maxlength)) len++;
  2244.      s[pos++] = (char) c;
  2245.      }
  2246.     }
  2247.     break;
  2248.   } /* switch */
  2249.   }
  2250.   s[len] = 0;
  2251.  }
  2252.  while ((c != CR) && (c != ESC));
  2253.  changecursor(FALSE);
  2254.  setcursor(0x2000);
  2255.  return(c != ESC);
  2256. } /* editstring */
  2257.  
  2258. /****************************************************************************
  2259.  save screen image , return pointer to allocated memory
  2260. */
  2261. char   *saveScrn (void)
  2262. {
  2263. unsigned srcSeg;
  2264. char     *saveArea;
  2265. struct videoconfig vc;
  2266. struct SREGS segregs;
  2267.  
  2268.   segread( &segregs );
  2269.   saveArea = (char *) malloc (4096);         /* alloceer ruimte */
  2270.   if (!saveArea)
  2271.   {
  2272.        show_error("Cannot allocate memory for screen save");
  2273.        return (char *) 0L;
  2274.   }
  2275.   _getvideoconfig( &vc );
  2276.   if (vc.mode== _TEXTMONO)
  2277.      srcSeg = 0xB000;                            /* monochroom scherm */
  2278.     else
  2279.      srcSeg = 0xB800;                 /* grafische text buffer */
  2280.   hide_mouse();
  2281.   movedata (srcSeg, 0, segregs.ss, (unsigned) saveArea, 4096);
  2282.   show_mouse();
  2283.   return (saveArea);                             /* return pointer !!!! */
  2284. }
  2285.  
  2286. /***************************************************************************
  2287.  restore screen if saveArea != NULL
  2288.  Return NULL pointer for update of saveArea to prevent multiple restores
  2289.  Memory is freed so else garbage would be restored if saveScrn and restScrn
  2290.  are not balanced
  2291. */
  2292. char *restScrn(char *saveArea)
  2293. {
  2294. unsigned destSeg;
  2295. struct videoconfig vc;
  2296. struct SREGS segregs;
  2297.  
  2298.   if (!saveArea) return (char *) 0L;
  2299.  
  2300.   segread( &segregs );
  2301.   _getvideoconfig( &vc );
  2302.   if (vc.mode== _TEXTMONO)
  2303.      destSeg = 0xB000;
  2304.   else
  2305.      destSeg = 0xB800;
  2306.   hide_mouse();
  2307.   movedata ( segregs.ss, (unsigned) saveArea, destSeg, 0, 4096);
  2308.   show_mouse();
  2309.   free (saveArea);
  2310.   return (char *) 0L;
  2311. }
  2312.  
  2313. /****************************************************************************
  2314.  Display current drive and working directory
  2315. */
  2316. void show_path( void )    /* this HAS some impact, searches disk on each call */
  2317. {
  2318.    char linebuf[_MAX_PATH];
  2319.    strcpy(linebuf,"");
  2320.    if (!_getdcwd( _getdrive(), linebuf, _MAX_PATH )) strcpy(linebuf,"");
  2321.    strlwr(linebuf);
  2322.    if (strlen(linebuf) >= 54)
  2323.    {
  2324.     linebuf[53]='';
  2325.     linebuf[54]='\0';
  2326.    }
  2327.    strcat(linebuf,"╞");
  2328.    while (strlen(linebuf)<56) strcat(linebuf,"═");
  2329.    _settextposition( 1, 15 );
  2330.    _settextcolor( (short) file_color );
  2331.    _setbkcolor( (long) screen_bg_color );
  2332.    outtextm(linebuf);
  2333. }
  2334.  
  2335. /***************************************************************************
  2336.  Check a full filename on illegal characters, name length, extension
  2337.  length, drive letter
  2338. */
  2339. int valid_filename( char *newname)
  2340. {
  2341.     char linebuf[_MAX_PATH];
  2342.     char *chrpointer;
  2343.     char illegal[20]={"\" +=[];|,<>/?*\\"};
  2344.     int length;
  2345.     register int teller;
  2346.  
  2347.     strcpy(linebuf,newname);
  2348.  
  2349.     if (strchr(illegal, linebuf[strlen(linebuf)-1])) return FALSE; /* check last character */
  2350.  
  2351.     if (strchr(linebuf,':'))   /* check drive */
  2352.     {
  2353.     if ((strchr(linebuf, ':') - linebuf)!=1) return FALSE; /* check place of : */
  2354.     linebuf[0] = (char) tolower((int) linebuf[0]);
  2355.     if ((linebuf[0] < 'a') || (linebuf[0] > 'z')) return FALSE;
  2356.     strcpy(linebuf,linebuf+2);  /* remove drive */
  2357.     }
  2358.  
  2359.     chrpointer = strtok( linebuf, "\\" );       /* Find first token */
  2360.     while( chrpointer != NULL )
  2361.     {
  2362.  
  2363.       chrpointer = strchr(linebuf,'.'); /* check extension */
  2364.       if (chrpointer)
  2365.       {
  2366.     if ((length=strlen(chrpointer+1))>3) return FALSE;           /* check size */
  2367.     for (teller=0;teller<length;teller++)
  2368.       if (strchr(illegal, *(chrpointer + 1 + teller))) return FALSE; /* check each character */
  2369.     *chrpointer = '\0';                                          /* remove extension */
  2370.       }
  2371.  
  2372.       chrpointer = strrchr(linebuf,'\\');        /* check name */
  2373.       if (!chrpointer) chrpointer=linebuf; /* no slash, start with first character */
  2374.       if (chrpointer)
  2375.       {
  2376.     if ((length=strlen(chrpointer+1))>8) return FALSE;           /* check size */
  2377.     for (teller=0;teller<length;teller++)
  2378.       if (strchr(illegal, *(chrpointer + 1 + teller))) return FALSE; /* check each character */
  2379.     *chrpointer = '\0';                                          /* remove name */
  2380.       }
  2381.  
  2382.      chrpointer = strtok( NULL, "\\" ); /* Find next token */
  2383.      }
  2384.     return TRUE;
  2385. }
  2386.  
  2387. /***************************************************************************
  2388.  Build a string with disk space free on current drive
  2389. */
  2390. int freespace( char *linebuf )
  2391. {
  2392.    int lastdrive;
  2393.    char scratch[_MAX_PATH];
  2394.    struct diskfree_t drvinfo;
  2395.    register int tel;
  2396.    int tel2;
  2397.  
  2398.    dos_error=0;
  2399.    dos_retries=0;
  2400.    lastdrive = _getdrive();
  2401.    if (!drvalid(lastdrive-1)) return FAILURE;
  2402.  
  2403.    _dos_getdiskfree( lastdrive, &drvinfo ); /* try to access the disk */
  2404.    if (dos_error) return FAILURE;
  2405.  
  2406.    sprintf( scratch,"%ld",
  2407.             (long)drvinfo.avail_clusters *
  2408.             drvinfo.sectors_per_cluster *
  2409.             drvinfo.bytes_per_sector );
  2410.    strrev( scratch );
  2411.    linebuf[0]='\0';
  2412.    tel2=0;
  2413.    for (tel=0;tel<(int) strlen(scratch);tel++)
  2414.    {
  2415.        if (tel && !(tel%3)) linebuf[tel2++]=',';   /* thousands separator */
  2416.        linebuf[tel2++]=scratch[tel];
  2417.    }
  2418.    if (linebuf[tel2-1]==',') linebuf[tel2-1]='\0'; /* blank trailing ',' */
  2419.       else linebuf[tel2]='\0';                     /* terminate string */
  2420.    strrev( linebuf );
  2421.    strcpy( scratch,linebuf );
  2422.    strcpy( linebuf," Disk space free: ");
  2423.    strcat( linebuf,scratch );
  2424.    strcat( linebuf," " );
  2425.    return SUCCESS;
  2426. }
  2427.  
  2428. void working( int mode )
  2429. {
  2430.    _settextposition( 1, 1 );
  2431.    _settextcolor( (short) file_color );
  2432.    _setbkcolor( screen_bg_color );
  2433.    if (mode) outtextm( "" );
  2434.    else outtextm( "╔" );
  2435. }
  2436.  
  2437. /***************************************************************************
  2438.  * Put shading under and at the right side of a box, if in COLOR mode
  2439.  */
  2440. void shadebox( short r1, short c1, short r2, short c2 )
  2441. {
  2442.   struct videoconfig vc;
  2443.   short int row, col;
  2444.   _getvideoconfig( &vc );
  2445.   if (vc.mode== _TEXTMONO) return;         /* monochroom scherm */
  2446.   hide_mouse();
  2447.   for (row=r1+1;row<=r2+1;row++)
  2448.   {
  2449.      shadechar(row,c2+1);
  2450.      shadechar(row,c2+2);
  2451.   }
  2452.   for (col=c1+1;col<=c2+1;col++) shadechar(r2+1,col);
  2453.   show_mouse();
  2454. }
  2455.  
  2456. /***************************************************************************
  2457.  * Direct video write, shade a character
  2458.  */
  2459. #define MAKELONG(a, b)  ((long)(((unsigned)a) \
  2460.                        | ((unsigned long)((unsigned)b)) << 16))
  2461. #define COLORTEXT_BUFFER   0XB800
  2462.  
  2463. void shadechar( int row, int col )
  2464. /* row      : row of location 1 to 25            */
  2465. /* col      : column of location 1 to 80            */
  2466. /* attrib : standard character attribute                */
  2467. {
  2468.     unsigned int offset; /* Offset from the segment address of
  2469.                             the desired video page */
  2470.     char far *y;         /* Long Pointer to the position in memory
  2471.                             where we will put the character and
  2472.                 it's attribute (next byte) */
  2473.     int pageno;  /* page number to load character into (0 to 3) */
  2474.     char attrib; /* standard character attribute        */
  2475.  
  2476.     pageno=0;
  2477.     attrib=0x08; /* background=black, textcolor=dark grey    */
  2478.     row--;  /* coord 1,1 is 0,0 for the function logic */
  2479.     col--;
  2480.  
  2481.     if (row<0 || row >24) return;   /* clip to screen boundary */
  2482.     if (col<0 || col >79) return;
  2483.  
  2484.     /* Calc the in-page offset w/page number offset and segment address */
  2485.     offset = (unsigned int) ((row * 160 )+(col*2)+(pageno*4096));
  2486.  
  2487.     /*    Set the attribute byte. See a DOS programmers reference for
  2488.     more information on video attributes. */
  2489.     offset++;
  2490.     y = (char far *)MAKELONG( offset, COLORTEXT_BUFFER);
  2491.     *y = attrib;
  2492. }
  2493.  
  2494. /* set working drive and directory and return a pointer to the first
  2495.  * character of the filename
  2496.  */
  2497. char *set_working_drive_and_dir( char *full_filename )
  2498. {
  2499.     char scratch[_MAX_PATH];
  2500.     char *slash;
  2501.     strcpy(scratch,full_filename); /* make drive & dir default */
  2502.     strupr(scratch);
  2503.     if (slash=strrchr(scratch, (int) '\\')) *slash='\0'; /* remove filename */
  2504.        else if (slash=strrchr(scratch, (int) ':')) *slash='\0'; /* maybe in format A:FILE.EXT */
  2505.     if (strlen(scratch)==1) strcat(scratch,":");               /* top directory ? */
  2506.     if (strlen(scratch)==2) strcat(scratch,"\\");           /* top directory ? */
  2507.     if (scratch[1]==':') _chdrive(scratch[0]-'A'+1);
  2508.     chdir(scratch);
  2509.     /* find filename */
  2510.     if (slash=strrchr(full_filename, (int) '\\')) return slash+1;  /* in format A:\FILE.EXT */
  2511.        else if (slash=strrchr(scratch, (int) ':')) return slash+1; /* maybe in format A:FILE.EXT */
  2512.     return 0L;
  2513. }
  2514.  
  2515. /**************************************************************************
  2516.  Change to parent directory and place cursor
  2517. */
  2518. void find_parent( int *current_page, int *filenumber, char *searchstring)
  2519. {
  2520.      register int counter;
  2521.      char linebuf[_MAX_PATH];
  2522.      char *p;
  2523.  
  2524.      _getdcwd( _getdrive(), linebuf, _MAX_PATH );
  2525.      if (p=strrchr(linebuf,'\\'))
  2526.      {
  2527.     memmove( linebuf, p+1, strlen(p+1)+1);
  2528.      } else return;                /* do nothing */
  2529.  
  2530.      if (!strlen(linebuf)) return; /* do nothing, already in root */
  2531.  
  2532.      chdir( ".." );
  2533.      extract_directory( searchstring );
  2534.      if (!number_of_files)
  2535.      {
  2536.      *current_page=0;
  2537.      *filenumber=1;
  2538.      }
  2539.      else
  2540.      {
  2541.      for (counter=1;counter<number_of_files;counter++)    /* should end at last file */
  2542.          if (!strcmp(find[counter].name,linebuf)) break;
  2543.      *filenumber=counter;
  2544.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  2545.      }
  2546. }
  2547.  
  2548.  
  2549. /*
  2550. **  DRVALID.C - validate disk drives
  2551. **  Original Copyright 1988-1991 by Bob Stout as part of
  2552. **  the MicroFirm Function Library (MFL)
  2553. **
  2554. **  This subset version is functionally identical to the
  2555. **  version originally published by the author in Tech Specialist
  2556. **  magazine and is donated to the public domain.
  2557. */
  2558.  
  2559.  
  2560. /*
  2561. **  getdrv()
  2562. **
  2563. **  Just as getcwd() returns the default directory, getdrv() returns
  2564. **  the current drive.
  2565. **
  2566. **  Arguments: None.
  2567. **
  2568. **  Returns:   Current drive (0 = A:, 1 = B:, etc.)
  2569. **
  2570. **  Side effects: none
  2571. */
  2572.  
  2573. int getdrv(void)
  2574. {
  2575.       union REGS regs;
  2576.  
  2577.       regs.h.ah = 0x19;
  2578.       intdos(®s, ®s);
  2579.       return (regs.h.al);
  2580. }
  2581.  
  2582. /*
  2583. **  chdrv()
  2584. **
  2585. **  Like chdir(), except changes drives rather than directories.
  2586. **
  2587. **  Arguments: 1 - target drive (0 = A:, 1 = B:, etc.)
  2588. **
  2589. **  Returns: SUCCESS or ERROR
  2590. **
  2591. **  Side effects: none
  2592. */
  2593.  
  2594. int chdrv(int drive)
  2595. {
  2596.       union REGS regs;
  2597.  
  2598.       regs.h.ah = 0x0e;
  2599.       regs.h.dl = (char)drive;
  2600.       intdos(®s, ®s);
  2601.       if (drive != getdrv())
  2602.         return ERROR;
  2603.       else  return SUCCESS;
  2604. }
  2605.  
  2606. /*
  2607. **  drvalid()
  2608. **
  2609. **  Verifies whether a logical disk drive is available without
  2610. **  triggering the DOS critical error handler.
  2611. **
  2612. **  Arguments: 1 - target drive (0 = A;, 1 = B:, etc.)
  2613. **
  2614. **  Returns:   TRUE  - drive is valid
  2615. **             FALSE - drive is invalid
  2616. **
  2617. **  Side effects: none
  2618. */
  2619.  
  2620. int drvalid(int drive)
  2621. {
  2622.       int original, result;
  2623.  
  2624.       original = getdrv();
  2625.       result   = (SUCCESS == chdrv(drive));
  2626.       chdrv(original);
  2627.       return result;
  2628. }
  2629.  
  2630. void ScrPutS (char *String, unsigned char Attr,
  2631.           unsigned char Row, unsigned char Col)
  2632. {
  2633.     register unsigned char A;
  2634.     unsigned char far *PtrVideoMode = (unsigned char far *) 0x00400049;
  2635.     unsigned char far *Video;
  2636.  
  2637.     A = Attr;
  2638.  
  2639.     FP_SEG (Video) = (*PtrVideoMode == 7) ? 0xb000 : 0xb800;
  2640.     FP_OFF (Video) = Row*160+Col*2;
  2641.  
  2642.     while (*String)
  2643.     {
  2644.     *Video++ = *String++;
  2645.     *Video++ = A;
  2646.     }
  2647. }
  2648.  
  2649. /* Ask for a drive */
  2650. /* In: key a..z pressed */
  2651. /* Out: drive number A=1, B=2 etc. or -1 if ESCaped */
  2652.  
  2653. int ask_drive_number( char * message)
  2654. {
  2655.     int key;
  2656.  
  2657.     do
  2658.     {
  2659.        _settextposition( 23, 25 );
  2660.        _settextcolor( (short) prompt_text_color );
  2661.        outtextm(message);
  2662.        _settextcolor( (short) file_color );
  2663.        _settextposition( 1, 1 );     /* prevent scroll-up from dos error */
  2664.        key = getkey();
  2665.        if (key<256) key = tolower(key);
  2666.     } while (((key < 'a') || (key > 'z')) &&(key != ESC));
  2667.     if (key!=ESC) return ( key - 'a' + 1);
  2668.     else return -1;
  2669. }
  2670.