home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / fs24 / fs1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-19  |  94.1 KB  |  3,169 lines

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