#include "diskpane.h" #include "keyboard.h" #include "mouse.h" #include #include #include #include #include #include #include #include #include void sort_by_extension( string_array & unsorted ); disk_pane:: disk_pane() { label.move_to( left(), top() ); directory.move_to( left(), top()+1 ); adopt( directory ); adopt( label ); _path_colour = DEFAULT_PATH_COLOUR; label.set_fill_char( ' ', _path_colour ); _looking_at_drive_list = false; _file_mask = "*.*"; resize( DEFAULT_HEIGHT, DEFAULT_WIDTH ); cd( current_directory() ); } int disk_pane:: take_control() { to_top(); draw_all_windows(); int event = 0; while( event != escape_key ) { if( key.pressed() ) { key.get(); event = process_key( key ); } else { mouse.poll(); event = process_mouse(); } } return event; } int disk_pane:: process_key( int keystroke ) { switch( keystroke ) { case return_key: if( !_looking_at_drive_list && directory.cursor_index() == 0 ) cd( ".." ); else cd( directory.list[directory.cursor_index()] ); break; case escape_key: break; default: directory.process_key( keystroke ); } draw_all_windows(); return keystroke; } int disk_pane:: process_mouse() { if( mouse.is_over( directory ) ) { if( mouse.left_double_click() ) return process_key( return_key ); else return directory.process_mouse(); } return mouse.event(); } int disk_pane:: cd( const char * new_dir ) { if( is_root_directory( _path ) && !_looking_at_drive_list && new_dir == ".." ) { _looking_at_drive_list = true; list_drives(); return 0; } if( is_root_directory( new_dir ) ) { char disk_letter; if( new_dir[1] == ':' ) disk_letter = new_dir[0]; else { char buffer[PATH_LENGTH]; getcwd( buffer, PATH_LENGTH ); disk_letter = buffer[0]; } if( !disk_ready( disk_letter ) ) { String message = " Drive "; message += disk_letter; message += ": not ready (no disk perhaps)"; if( (int)message.length() < label.width() ) message += replicate( ' ', label.width() - message.length() ); label.put_text( message, 0, red_bg+bright_white_fg ); return -1; } } bool error = chdir( new_dir ); if( error ) return error; _looking_at_drive_list = false; String original_dir = _path; _path = current_directory(); refresh(); String old_dir = upcase( original_dir ); old_dir = old_dir.before( DIRSLASH, -1 ); if( old_dir.contains( DIRSLASH ) ) old_dir = old_dir.after( DIRSLASH, -1 ); directory.cursor_to( directory.index_of( old_dir ) ); return 0; } bool is_root_directory( const char * dir_name ) { if( ( ( strlen( dir_name ) == 1 ) && ( dir_name[0] == DIRSLASH ) ) || ( strlen( dir_name ) == 3 && dir_name[1] == ':' && ( dir_name[2] == DIRSLASH ) ) ) { return true; } if( strcmp( dir_name, ".." ) == 0 ) { char buffer[PATH_LENGTH]; String current_dir; current_dir = getcwd( buffer, PATH_LENGTH ); if( current_dir.freq( "/" ) == 1 ) return true; } return false; } void disk_pane:: resize( int new_width, int new_height ) { directory.resize( new_width, new_height-1 ); label.resize( new_width, 1 ); screen_pane::resize( new_width, new_height ); update_directory_name(); } void disk_pane:: set_file_mask( const char * wildcard ) { _file_mask = wildcard; } void disk_pane:: set_path_colour( char colour ) { _path_colour = colour; label.set_fill_char( ' ', colour ); } void disk_pane:: refresh() { if( _looking_at_drive_list ) { list_drives(); } else { get_file_list(); update_directory_name(); } directory.refresh_text(); } void disk_pane:: list_drives() { directory.list = available_drives(); directory.refresh_text(); label.put_text( " Available drives", 0, _path_colour ); directory.cursor_to( directory.list.index( _path ).y ); } string_array get_file_list( const char * file_mask ) { char filespec[PATH_LENGTH]; string_array files; struct find_t file_info; strcpy( filespec, file_mask ); int failed = _dos_findfirst( filespec, _A_HIDDEN|_A_SYSTEM|_A_SUBDIR, &file_info ); while( !failed ) { if( strcmp( file_info.name, "." ) && strcmp( file_info.name, ".." ) ) { if( !(file_info.attrib & _A_SUBDIR) ) files.add_line( downcase( file_info.name ) ); } failed = _dos_findnext( &file_info ); } return files; } void disk_pane:: get_file_list() { char filespec[PATH_LENGTH]; string_array files, subdirs; struct find_t file_info; strcpy( filespec, _file_mask ); int failed = _dos_findfirst( filespec, _A_HIDDEN|_A_SYSTEM|_A_SUBDIR, &file_info ); while( !failed ) { if( strcmp( file_info.name, "." ) && strcmp( file_info.name, ".." ) ) { if( file_info.attrib & _A_SUBDIR ) subdirs.add_line( file_info.name ); else files.add_line( downcase( file_info.name ) ); } failed = _dos_findnext( &file_info ); } subdirs.alpha_sort(); sort_by_extension( files ); directory.list.resize( 0 ); directory.list += " UP "; directory.list += subdirs; directory.list += files; } void disk_pane:: update_directory_name() { _path = current_directory(); if( (int)_path.length() > width() && width() > 0 ) { String last_bit = _path.after( (int)(_path.length() - width()) - 1 ); label.put_text( ' ' + last_bit, 0, _path_colour ); } else label.put_text( ' ' + _path, 0, _path_colour ); } string_array available_drives() { string_array disk_list; char drive = 'a'; char buffer[2] = { '\0', '\0' }; while( drive <= 'z' ) { if( drive_present( drive ) ) { buffer[0] = drive; disk_list += buffer; disk_list[disk_list.height()-1] += ":\\"; } drive++; } return disk_list; } bool drive_present( char drive_letter ) { int drive_number = ( toupper( drive_letter ) - 'A' ) + 1; if( drive_number < 1 || drive_number > 26 ) return false; if( floppy( drive_letter ) ) if( floppy_drive_present( drive_letter ) ) return true; else return false; char drive_name[16]; drive_name[0] = toupper( drive_letter ); drive_name[1] = '\0'; strcat( drive_name, ":\\*" ); struct find_t file_info; int find_status = _dos_findfirst( drive_name, _A_HIDDEN|_A_SYSTEM|_A_SUBDIR, &file_info ); return ( find_status == 0 || find_status == 0x12 ); } bool disk_ready( char drive_letter ) { if( drive_letter == '!' ) { char buffer[PATH_LENGTH]; getcwd( buffer, PATH_LENGTH ); drive_letter = buffer[0]; } else { drive_letter = tolower( drive_letter ); if( drive_letter < 'a' || drive_letter > 'z' ) return false; } if( floppy( drive_letter ) && floppy_disk_ready( drive_letter ) ) return true; char drive_name[16]; drive_name[0] = toupper( drive_letter ); drive_name[1] = '\0'; strcat( drive_name, ":\\*" ); struct find_t file_info; int failed = _dos_findfirst( drive_name, 0x3f, &file_info ); return !failed; } bool floppy_drive_present( char drive_letter ) { int drive_number = ( toupper( drive_letter ) - 'A' ) + 1; if( drive_number < 1 || drive_number > 26 ) return false; if( floppy( drive_letter ) ) if( drive_number <= number_of_floppy_drives() ) return true; return false; } bool floppy( char drive_letter ) { int drive_number = ( toupper( drive_letter ) - 'A' ) + 1; if( drive_number < 1 || drive_number > 26 ) return false; union REGS reg; reg.h.ah = 0x44; reg.h.al = 0x08; reg.h.bl = drive_number; int86( 0x21, ®, ® ); return !reg.h.al; } // this enables me to check for a disk in the floppy drive, // without causing a big emergency for dos if there isn't one bool floppy_disk_ready( char drive_letter ) { if( !floppy_drive_present( drive_letter ) ) return false; int drive_number = toupper( drive_letter ) - 'A'; union REGS reg; bool disk_present = false; // knock three times to be sure int i = 0; while( !disk_present && i < 3 ) { // reset drive reg.w.ax = 0x0000; reg.w.dx = drive_number; int86( 0x13, ®, ® ); // attempt to verify a sector reg.h.ah = 0x04; reg.h.al = 0x01; reg.w.cx = 0x0001; reg.w.dx = drive_number; int86( 0x13, ®, ® ); // get error flag disk_present = !reg.h.cflag; i++; } // one last reset, to ensure a smooth recovery // when there is no disk in the drive reg.w.ax = 0x0000; reg.w.dx = drive_number; int86( 0x13, ®, ® ); return disk_present; } int number_of_floppy_drives() { union REGS reg; int86( 0x11, ®, ® ); if( !( reg.w.ax & 0x1 ) ) return 0; else return ( ( reg.w.ax >> 6 ) & 0x3 ) + 1; } int extension_cmp( const void * e1, const void * e2 ) { String s1 = *(const String*)e1; String s2 = *(const String*)e2; int difference = strcmp( (String)s1.after( '.' ), (String)s2.after( '.' ) ); if( difference ) return difference; if( s1.contains( '.' ) ) s1 = s1.before( '.' ); if( s2.contains( '.' ) ) s2 = s2.before( '.' ); return strcmp( s1, s2 ); } void sort_by_extension( string_array & unsorted ) { qsort( unsorted, unsorted.height(), sizeof(String), extension_cmp ); } String disk_pane:: get_item( int index ) { if( index == cursor_location ) index = directory.cursor_index(); if( index >= 0 && index < directory.list.height() ) return _path + directory.list[index]; String error_string = "get_item(int): file number out of bounds."; return error_string; } String disk_pane:: path() { return _path; } bool is_a_file( const char * candidate ) { struct find_t file_info; char file_name[PATH_LENGTH]; strcpy( file_name, candidate ); int failed = _dos_findfirst( file_name, _A_HIDDEN|_A_SYSTEM, &file_info ); if( failed ) return false; return !( file_info.attrib & _A_SUBDIR ) && !( is_root_directory( candidate ) ); } String full_path( const char * file_name ) { String full_name = file_name; String saved_cwd, path_part, last_part; if( file_name[1] == ':' ) return full_name; if( full_name.index( DIRSLASH ) == not_found ) { path_part = current_directory(); full_name = path_part + full_name; } else { last_part = full_name.after( DIRSLASH, -1 ); path_part = full_name.through( DIRSLASH, -1 ); saved_cwd = current_directory(); bool error = chdir( path_part ); if( error ) return full_name; path_part = current_directory(); chdir( saved_cwd ); full_name = path_part + last_part; } return full_name; } String current_directory() { char buffer[PATH_LENGTH]; String path = getcwd( buffer, PATH_LENGTH ); path.gsub( '/', DIRSLASH ); if( path[path.length()-1] != DIRSLASH ) path += DIRSLASH; return path; }