#include "s_array.h" #include "keyboard.h" #include #include #include #include const int not_found = -1; const point point_not_found = { not_found, not_found }; #define MAX_FILE_LINE_LENGTH 4096 #define DEFAULT_TAB_WIDTH 3 string_array::string_array() { array = 0; _height = 0; set_tab_width( DEFAULT_TAB_WIDTH ); actual_height = 0; } string_array::string_array( int height ) { array = 0; _height = 0; actual_height = 0; resize( height ); } string_array::string_array( const string_array & other ) { array = 0; _height = 0; actual_height = 0; operator=( other ); } string_array::~string_array() { resize( 0 ); } string_array & string_array:: operator=( const string_array & other ) { resize( other.height() ); int i = 0; while( i < _height ) { array[i] = other.array[i]; i++; } return *this; } string_array & string_array:: operator+=( const string_array & other ) { int old_height = height(); resize_and_keep( height() + other.height() ); int i = 0; while( i < other.height() ) { array[i+old_height] = other.array[i]; i++; } return *this; } string_array& string_array:: operator+=( const char * new_line ) { resize_and_keep( height() + 1 ); array[height() - 1] = new_line; return *this; } String string_array:: as_a_big_string() { String big_string; int i = 0; while( i < _height ) { big_string += array[i] + '\n'; i++; } return big_string; } int big_string_index( const String & big_string, point pos ) { if( !big_string || pos.y < 0 || pos.y > big_string.freq( '\n' ) || pos.x < 0 ) return not_found; int index = 0; int y = 0; while( y < pos.y && index != not_found ) { index = big_string.index( '\n', index ); if( index == not_found ) return not_found; index++; if( index == (int)big_string.length() - 1 ) return not_found; y++; } if( index + pos.x >= (int)big_string.length() ) return not_found; else return index + pos.x; } int big_string_index( String & big_string, int x, int y ) { point pos = { x, y }; return big_string_index( big_string, pos ); } point big_string_pos( String & big_string, int index ) { point translation = { not_found, not_found }; if( index < 0 || index >= (int)big_string.length() ) return translation; String segment = big_string.before( index ); translation.x = index; translation.y = segment.freq( '\n' ); if( translation.y > 0 ) { segment = segment.after( '\n', -1 ); translation.x = segment.length(); } return translation; } bool string_array:: resize( int new_height ) { if( new_height < 0 ) return true; if( new_height == 0 ) { if( array ) delete( array ); actual_height = 0; _height = 0; array = 0; return false; } if( new_height < _height ) { int i = 0; while( i < _height ) { array[i] = ""; i++; } _height = new_height; return false; } if( new_height <= actual_height ) { _height = new_height; return false; } int new_actual_height = 2 * actual_height; if( new_actual_height == 0 ) new_actual_height = DEFAULT_INITIAL_HEIGHT; if( new_actual_height < new_height ) new_actual_height = new_height; String * temp = new String[new_actual_height]; if( !temp ) return true; if( array ) delete [] array; actual_height = new_actual_height; _height = new_height; array = temp; return false; } bool string_array:: resize_and_keep( int new_height ) { if( new_height < 0 ) return true; if( new_height < _height ) { int i = new_height; while( i < _height ) { array[i] = ""; i++; } _height = new_height; return false; } if( new_height <= actual_height ) { _height = new_height; return false; } int new_actual_height = 2 * actual_height; if( new_actual_height == 0 ) new_actual_height = DEFAULT_INITIAL_HEIGHT; if( new_actual_height < new_height ) new_actual_height = new_height; String * temp = new String[new_actual_height]; if( !temp ) return true; if( array ) { int max = _height; if( max > new_height ) max = new_height; int i = 0; while( i < max ) { temp[i] = array[i]; i++; } delete [] array; } actual_height = new_actual_height; _height = new_height; array = temp; return false; } bool string_array:: read_file( const char * file_name ) { FILE * stream = fopen( file_name, "rt" ); if( !stream ) return true; bool error_status = read_file( stream ); fclose( stream ); return error_status; } bool string_array:: write_file( const char * file_name ) { int drive; String path = file_name; if( path.index( ':' ) == 1 ) drive = toupper( path[0] ) - 'A'; else drive = getdisk(); _diskfree_t space_data; bool error = _dos_getdiskfree( drive, &space_data ); int space_available = space_data.avail_clusters * space_data.sectors_per_cluster * space_data.bytes_per_sector; if( error || space_available <= size() ) { fprintf( stderr, "Can't write %s: no disk space perhaps.\n", file_name ); key.get(); return true; } FILE * stream = fopen( file_name, "wt" ); if( !stream ) return true; error = write_file( stream ); fclose( stream ); return error; } bool string_array:: read_file( FILE* stream ) { if( !stream ) return true; char buffer[MAX_FILE_LINE_LENGTH]; int linecount = 0; while( fgets( buffer, MAX_FILE_LINE_LENGTH, stream ) ) linecount++; rewind( stream ); resize( linecount ); int i = 0; while( i < linecount ) { fgets( buffer, MAX_FILE_LINE_LENGTH, stream ); array[i] = buffer; array[i] = array[i].before( "\n" ); i++; } return false; } bool string_array:: read_file_from( const char * file_name, int start, int height ) { FILE * stream = fopen( file_name, "rt" ); if( !stream ) return true; char buffer[MAX_FILE_LINE_LENGTH]; bool file_error = false; int line_count = 0; while( !file_error && line_count < start ) { file_error = !fgets( buffer, MAX_FILE_LINE_LENGTH, stream ); line_count++; } bool error = resize( height ); if( error ) return true; line_count = 0; int i = start; int finish = start + height; while( !file_error && i < finish ) { file_error = !fgets( buffer, MAX_FILE_LINE_LENGTH, stream ); array[line_count] = buffer; array[line_count] = array[line_count].before( "\n" ); line_count++; i++; } fclose( stream ); return false; } bool string_array:: write_file( FILE* stream ) { if( !stream ) return true; int i = 0; while( i < _height ) { fputs( array[i] + '\n', stream ); i++; } return false; } void string_array:: strip_newlines() { int i = 0; while( i < height() ) { if( array[i].contains( "\n" ) ) array[i] = array[i].before( "\n" ); i++; } } int string_array:: width() { int intest = 0; int i = 0; while( i < height() ) { if( (int)array[i].length() > intest ) intest = array[i].length(); i++; } return intest; } point string_array:: index( const char * substring, int x, int y ) { point end_point = { not_found, not_found }; bool error = check_xy( x, y ); if( error ) return end_point; end_point.x = array[y].index( substring, x ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; while( y < height() ) { end_point.x = array[y].index( substring ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; } end_point.x = not_found; end_point.y = not_found; return end_point; } point string_array:: ci_index( const char * substring_text, int x, int y ) { point end_point = { not_found, not_found }; bool error = check_xy( x, y ); if( error ) return end_point; String substring = upcase( substring_text ); String next_line = upcase( array[y] ); end_point.x = next_line.index( substring, x ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; while( y < height() ) { next_line = upcase( array[y] ); end_point.x = next_line.index( substring ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; } end_point.x = not_found; end_point.y = not_found; return end_point; } point string_array:: index( const Regex & pattern, int x, int y ) { point end_point = { not_found, not_found }; bool error = check_xy( x, y ); if( error ) return end_point; end_point.x = array[y].index( pattern, x ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; while( y < height() ) { end_point.x = array[y].index( pattern ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; } end_point.x = not_found; end_point.y = not_found; return end_point; } point string_array:: index( char character, int x, int y ) { point end_point = { not_found, not_found }; bool error = check_xy( x, y ); if( error ) return end_point; end_point.x = array[y].index( character, x ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; while( y < height() ) { end_point.x = array[y].index( character ); if( end_point.x != not_found ) { end_point.y = y; return end_point; } y++; } return end_point; } void string_array:: insert_at( char character, int x, int y ) { if( y >= 0 && y < height() ) { if( x > (int)array[y].length() ) array[y] += replicate( ' ', x - array[y].length() ); array[y] = array[y].before( (int)x ) + character + array[y].from( (int)x ); } } void string_array:: delete_at( int x, int y ) { if( y >= 0 && y < height() ) { if( x >= (int)array[y].length() ) array[y] += replicate( ' ', x - array[y].length() ); array[y] = array[y].before( (int)x ) + array[y].after( (int)x ); } } void string_array:: add_line( const char * new_line ) { resize_and_keep( height() + 1 ); array[height()-1] = new_line; } void string_array:: insert_line_at( const char * new_line, int y ) { if( y < 0 || y > height() ) y = height(); resize_and_keep( height() + 1 ); int line_number = height() - 1; while( line_number > y ) { array[line_number] = array[line_number-1]; line_number--; } array[y] = new_line; } void string_array:: delete_line_at( int y ) { if( y < 0 || y >= height() ) return; int top = height() - 1; while( y < top ) { array[y] = array[y+1]; y++; } resize_and_keep( height() - 1 ); } int string_array:: remove_repeats() { int top = height() - 1; int i = 0, j; while( i < top ) { j = i + 1; while( j <= top ) { if( array[j] == array[i] ) { delete_line_at( j ); top--; } else j++; } i++; } return ( height() - 1 ) - top; } string_array string_array:: height_wrap( int column_width, int max_height ) { string_array short_one( max_height ); String next_bit; int i = 0, j; while( i < max_height ) { j = i; while( j < height() ) { next_bit = array[j]; if( (int)next_bit.length() > column_width ) next_bit = next_bit.before( (int)column_width ); else next_bit += replicate( ' ', column_width - next_bit.length() ); short_one[i] += next_bit; j += max_height; } i++; } return short_one; } int sort_function( const void * e1, const void * e2 ) { return strcmp( *((String*)e1), *((String*)e2) ); } void string_array:: alpha_sort() { qsort( array, height(), sizeof(String), sort_function ); } void string_array:: to_upper() { int i = 0; while( i < _height ) { array[i] = upcase( array[i] ); i++; } } void string_array:: to_lower() { int i = 0; while( i < _height ) { array[i] = downcase( array[i] ); i++; } } string_array string_array:: from( int start, int section_height ) { string_array empty; if( start < 0 || start + section_height >= height() ) return empty; string_array section( section_height ); int i = start, j = 0; while( j < section_height ) { section[j] = array[i]; j++; i++; } return section; } void string_array:: detab() { int tab_pos; int number_of_spaces; int i = 0; while( i < _height ) { tab_pos = array[i].index( '\t' ); while( tab_pos != not_found ) { number_of_spaces = _tab_width - ( tab_pos % _tab_width ); array[i].at( '\t' ) = replicate( ' ', number_of_spaces ); if( tab_pos == (int)array[i].length() - 1 ) break; tab_pos = array[i].index( '\t', tab_pos + 1 ); } i++; } } void string_array:: set_tab_width( int new_width ) { _tab_width = new_width; } int string_array:: tab_width() { return _tab_width; } string_array string_to_array( String & big_string ) { string_array array; int start_of_line = 0; int end_of_line = big_string.index( '\n' ); while( end_of_line != not_found ) { array += (String)big_string.at( start_of_line, end_of_line - start_of_line); if( end_of_line == (int)big_string.length() - 1 ) break; start_of_line = end_of_line + 1; end_of_line = big_string.index( '\n', end_of_line+1 ); } return array; } point array_pos( string_array _array, int index ) { point failed = { not_found, not_found }; if( index < 0 ) return failed; int length_so_far = 0; int height = _array.height(); point pos = { 0, 0 }; while( pos.y < height ) { if( (int)_array[pos.y].length() + length_so_far > index ) { pos.x = index - length_so_far; break; } length_so_far += _array[pos.y].length() + 1; pos.y++; } if( pos.y == height ) return failed; else return pos; } bool string_array:: check_xy( int & x, int & y ) { if( y < 0 || y >= height() ) return true; if( x >= (int)array[y].length() ) { if( y >= height() - 1 ) return true; else { y++; x = 0; } } return false; } int string_array:: size() { int file_size = 0; int i = 0; while( i < _height ) { file_size += array[i].length() + 1; i++; } return file_size; }