back to scratko.xyz
aboutsummaryrefslogtreecommitdiff
path: root/columns.c
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2025-09-08 01:44:13 +0300
committerscratko <m@scratko.xyz>2025-09-08 01:44:13 +0300
commit6b7b0ea022ad18b30622acd5e1354ff64cf14d86 (patch)
tree3d8a8cdfc9985b7c242e66e3734c5cefcda21215 /columns.c
downloadls-imitation-master.tar.gz
ls-imitation-master.tar.bz2
ls-imitation-master.zip
Initial commitHEADmaster
Diffstat (limited to 'columns.c')
-rw-r--r--columns.c173
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);
+}