#include "columns.h" #include "data_struct.h" #include #include /* column indexes used for alignment */ enum column_type { col_links = 1, col_owner = 2, col_group = 3, col_size = 4 }; /* * find pointer to beginning of column in line. * pad_spaces -- column index */ static char *find_start_column_pos(char *line, enum column_type pad_spaces) { size_t found_whitespace = 0; while(found_whitespace != pad_spaces) { if(*line == ' ') { ++found_whitespace; /* skip consecutive spaces */ while(*line == ' ') ++line; } else ++line; } return line; } /* Find pointer to the end of current column */ static char *find_end_column_pos(char *line) { while(*line && *line != ' ') ++line; return line; } /* * Count number of symbols in column. * Special case: when dealing with major and minor numbers (contains ','). */ static size_t compute_symbols(const char *line, enum column_type pad_spaces) { size_t symbols_counter = 0; while(*line && *line != ' ') { ++symbols_counter; /* extra space for alignment after comma */ if(*line == ',' && pad_spaces == col_size) { ++symbols_counter; ++line; } ++line; } return symbols_counter; } /* scan all items and find maximum column width */ static size_t find_max_column(struct file_item *list, enum column_type pad_spaces) { size_t max_columns = 0; size_t current_columns = 0; char *pos = NULL; while(list) { pos = find_start_column_pos(list->info_line, pad_spaces); current_columns = compute_symbols(pos, pad_spaces); if(current_columns > max_columns) max_columns = current_columns; list = list->next; } return max_columns; } /* check if column must be left aligned */ static int is_left_alignment(enum column_type pad_spaces) { return pad_spaces == col_owner || pad_spaces == col_group; } /* calculate remaining string length including null symbol */ static size_t get_remaining_line_length(const char *line) { size_t symbols_counter = 0; while(*line) { ++symbols_counter; ++line; } /* null-terminated */ ++symbols_counter; return symbols_counter; } /* fill alignment gap with spaces */ static void pad_with_spaces(char *pos, int alignment) { for (; alignment > 0; --alignment, ++pos) *pos = ' '; } /* shift contents to the right and pad with spaces */ static void shift_and_pad(char *insert_pos, size_t alignment, char *start_buffer_pos) { size_t remaining_symbols = get_remaining_line_length(insert_pos); size_t offset = (size_t)(insert_pos - start_buffer_pos); if (offset + remaining_symbols + alignment <= buffer_size) { memmove(insert_pos + alignment, insert_pos, remaining_symbols); pad_with_spaces(insert_pos, alignment); } } /* insert spaces after column (left alignment) */ static void left_align(char *column_pos, size_t alignment, char *start_buffer_pos) { char *end_column_pos = find_end_column_pos(column_pos); shift_and_pad(end_column_pos, alignment, start_buffer_pos); } /* insert spaces before column (right alignment) */ static void right_align(char *column_pos, size_t alignment, char *start_buffer_pos) { shift_and_pad(column_pos, alignment, start_buffer_pos); } /* align single column*/ static void align_column(struct file_item *list, enum column_type pad_spaces) { char *column_pos = NULL; size_t max_columns = find_max_column(list, pad_spaces); size_t current_columns = 0; size_t different = 0; if(max_columns == 1) return; while(list) { column_pos = find_start_column_pos(list->info_line, pad_spaces); current_columns = compute_symbols(column_pos, pad_spaces); different = max_columns - current_columns; if(different > 0) { if(is_left_alignment(pad_spaces)) left_align(column_pos, different, list->info_line); else right_align(column_pos, different, list->info_line); } list = list->next; } } /* * Align all columns (links, owner, group, size). * Must be called after building info_line */ void align_columns(struct file_item *list) { align_column(list, col_links); align_column(list, col_owner); align_column(list, col_group); align_column(list, col_size); }