diff options
Diffstat (limited to 'columns.c')
-rw-r--r-- | columns.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/columns.c b/columns.c new file mode 100644 index 0000000..fe35070 --- /dev/null +++ b/columns.c @@ -0,0 +1,173 @@ +#include "columns.h" +#include "data_struct.h" + +#include <string.h> +#include <stddef.h> + +/* 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); +} |