Correct column width for tab completion and ls
This commit was genuinely broken at the time (not related to our build system): sysdeps/linux/Config.in "fileutils/Config.in" dosyasini kaynak gosteriyor ama bu dosya repoda hic var olmadi (2002-12-05 - 2003-02-15 arasi orijinal yazar hatasi, 3238ea167 ile duzeltildi)
No binary (build failed)
—
(log yok)
| @@ -43,11 +43,9 @@ | |
| enum { | |
| TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ | |
| - | COLUMN_WIDTH = 14, /* default if AUTOWIDTH not defined */ |
| COLUMN_GAP = 2, /* includes the file type char */ | |
| }; | |
| - | |
| /************************************************************************/ | |
| #include <sys/types.h> | |
| @@ -167,7 +165,7 @@ struct dnode { /* the basic node */ | |
| }; | |
| typedef struct dnode dnode_t; | |
| - | static struct dnode **list_dir(char *); |
| + | static struct dnode **list_dir(const char *); |
| static struct dnode **dnalloc(int); | |
| static int list_single(struct dnode *); | |
| @@ -186,14 +184,12 @@ static unsigned int time_fmt; | |
| static unsigned int follow_links = FALSE; | |
| #endif | |
| - | static unsigned short column = 0; |
| - | |
| #ifdef CONFIG_FEATURE_AUTOWIDTH | |
| static unsigned short terminal_width = TERMINAL_WIDTH; | |
| - | static unsigned short column_width = COLUMN_WIDTH; |
| static unsigned short tabstops = COLUMN_GAP; | |
| #else | |
| - | static unsigned short column_width = COLUMN_WIDTH; |
| + | #define tabstops COLUMN_GAP |
| + | #define terminal_width TERMINAL_WIDTH |
| #endif | |
| static int status = EXIT_SUCCESS; | |
| @@ -202,35 +198,31 @@ static int status = EXIT_SUCCESS; | |
| static unsigned long ls_disp_hr = 0; | |
| #endif | |
| - | static int my_stat(struct dnode *cur) |
| + | static struct dnode *my_stat(char *fullname, char *name) |
| { | |
| + | struct stat dstat; |
| + | struct dnode *cur; |
| + | |
| #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS | |
| if (follow_links) { | |
| - | if (stat(cur->fullname, &cur->dstat)) { |
| - | perror_msg("%s", cur->fullname); |
| + | if (stat(fullname, &dstat)) { |
| + | perror_msg("%s", fullname); |
| status = EXIT_FAILURE; | |
| - | free(cur->fullname); |
| - | free(cur); |
| - | return -1; |
| + | return 0; |
| } | |
| } else | |
| #endif | |
| - | if (lstat(cur->fullname, &cur->dstat)) { |
| - | perror_msg("%s", cur->fullname); |
| + | if (lstat(fullname, &dstat)) { |
| + | perror_msg("%s", fullname); |
| status = EXIT_FAILURE; | |
| - | free(cur->fullname); |
| - | free(cur); |
| - | return -1; |
| - | } |
| return 0; | |
| - | } |
| - | |
| - | static void newline(void) |
| - | { |
| - | if (column > 0) { |
| - | putchar('\n'); |
| - | column = 0; |
| } | |
| + | |
| + | cur = (struct dnode *) xmalloc(sizeof(struct dnode)); |
| + | cur->fullname = fullname; |
| + | cur->name = name; |
| + | cur->dstat = dstat; |
| + | return cur; |
| } | |
| /*----------------------------------------------------------------------*/ | |
| @@ -239,7 +231,6 @@ static char fgcolor(mode_t mode) | |
| { | |
| /* Check wheter the file is existing (if so, color it red!) */ | |
| if (errno == ENOENT) { | |
| - | errno = 0; |
| return '\037'; | |
| } | |
| if (LIST_EXEC && S_ISREG(mode) | |
| @@ -271,24 +262,6 @@ static char append_char(mode_t mode) | |
| } | |
| #endif | |
| - | /*----------------------------------------------------------------------*/ |
| - | static void nexttabstop(void) |
| - | { |
| - | static short nexttab = 0; |
| - | int n = 0; |
| - | |
| - | if (column > 0) { |
| - | n = nexttab - column; |
| - | if (n < 1) |
| - | n = 1; |
| - | while (n--) { |
| - | putchar(' '); |
| - | column++; |
| - | } |
| - | } |
| - | nexttab = column + column_width + COLUMN_GAP; |
| - | } |
| - | |
| /*----------------------------------------------------------------------*/ | |
| static int is_subdir(struct dnode *dn) | |
| { | |
| @@ -437,7 +410,11 @@ static int sortcmp(struct dnode *d1, struct dnode *d2) | |
| cmp = 1; | |
| if (dif == 0) { | |
| /* sort by name- may be a tie_breaker for time or size cmp */ | |
| + | #ifdef CONFIG_LOCALE_SUPPORT |
| + | dif = strcoll(d1->name, d2->name); |
| + | #else |
| dif = strcmp(d1->name, d2->name); | |
| + | #endif |
| if (dif > 0) | |
| cmp = 1; | |
| if (dif < 0) | |
| @@ -479,46 +456,40 @@ static void shellsort(struct dnode **dn, int size) | |
| static void showfiles(struct dnode **dn, int nfiles) | |
| { | |
| int i, ncols, nrows, row, nc; | |
| - | |
| - | #ifdef CONFIG_FEATURE_AUTOWIDTH |
| - | int len; |
| - | #endif |
| + | int column = 0; |
| + | int nexttab = 0; |
| + | int column_width = 0; /* for STYLE_LONG and STYLE_SINGLE not used */ |
| if (dn == NULL || nfiles < 1) | |
| return; | |
| - | #ifdef CONFIG_FEATURE_AUTOWIDTH |
| + | switch (style_fmt) { |
| + | case STYLE_LONG: /* one record per line, extended info */ |
| + | case STYLE_SINGLE: /* one record per line */ |
| + | ncols = 1; |
| + | break; |
| + | default: |
| /* find the longest file name- use that as the column width */ | |
| - | column_width = 0; |
| for (i = 0; i < nfiles; i++) { | |
| - | len = strlen(dn[i]->name) + |
| + | int len = strlen(dn[i]->name) + |
| ((list_fmt & LIST_INO) ? 8 : 0) + | |
| ((list_fmt & LIST_BLOCKS) ? 5 : 0); | |
| if (column_width < len) | |
| column_width = len; | |
| } | |
| - | ncols = (int) (terminal_width / (column_width + COLUMN_GAP)); |
| - | #else |
| - | ncols = TERMINAL_WIDTH; |
| - | #endif |
| - | switch (style_fmt) { |
| - | case STYLE_LONG: /* one record per line, extended info */ |
| - | case STYLE_SINGLE: /* one record per line */ |
| - | ncols = 1; |
| - | break; |
| + | column_width += tabstops; |
| + | ncols = (int) (terminal_width / column_width); |
| } | |
| if (ncols > 1) { | |
| nrows = nfiles / ncols; | |
| + | if ((nrows * ncols) < nfiles) |
| + | nrows++; /* round up fractionals */ |
| } else { | |
| nrows = nfiles; | |
| ncols = 1; | |
| } | |
| - | if ((nrows * ncols) < nfiles) |
| - | nrows++; /* round up fractionals */ |
| - | if (nrows > nfiles) |
| - | nrows = nfiles; |
| for (row = 0; row < nrows; row++) { | |
| for (nc = 0; nc < ncols; nc++) { | |
| /* reach into the array based on the column and row */ | |
| @@ -526,11 +497,19 @@ static void showfiles(struct dnode **dn, int nfiles) | |
| if (disp_opts & DISP_ROWS) | |
| i = (row * ncols) + nc; /* display across row */ | |
| if (i < nfiles) { | |
| - | nexttabstop(); |
| - | list_single(dn[i]); |
| + | if (column > 0) { |
| + | nexttab -= column; |
| + | while (nexttab--) { |
| + | putchar(' '); |
| + | column++; |
| + | } |
| } | |
| + | nexttab = column + column_width; |
| + | column += list_single(dn[i]); |
| } | |
| - | newline(); |
| + | } |
| + | putchar('\n'); |
| + | column = 0; |
| } | |
| } | |
| @@ -580,7 +559,7 @@ static void showdirs(struct dnode **dn, int ndirs) | |
| } | |
| /*----------------------------------------------------------------------*/ | |
| - | static struct dnode **list_dir(char *path) |
| + | static struct dnode **list_dir(const char *path) |
| { | |
| struct dnode *dn, *cur, **dnp; | |
| struct dirent *entry; | |
| @@ -599,18 +578,21 @@ static struct dnode **list_dir(char *path) | |
| return (NULL); /* could not open the dir */ | |
| } | |
| while ((entry = readdir(dir)) != NULL) { | |
| + | char *fullname; |
| + | |
| /* are we going to list the file- it may be . or .. or a hidden file */ | |
| - | if ((strcmp(entry->d_name, ".") == 0) && !(disp_opts & DISP_DOT)) |
| - | continue; |
| - | if ((strcmp(entry->d_name, "..") == 0) && !(disp_opts & DISP_DOT)) |
| + | if (entry->d_name[0] == '.') { |
| + | if ((entry->d_name[1] == 0 || ( |
| + | entry->d_name[1] == '.' |
| + | && entry->d_name[2] == 0)) |
| + | && !(disp_opts & DISP_DOT)) |
| continue; | |
| - | if ((entry->d_name[0] == '.') && !(disp_opts & DISP_HIDDEN)) |
| + | if (!(disp_opts & DISP_HIDDEN)) |
| continue; | |
| - | cur = (struct dnode *) xmalloc(sizeof(struct dnode)); |
| - | cur->fullname = concat_path_file(path, entry->d_name); |
| - | cur->name = cur->fullname + |
| - | (strlen(cur->fullname) - strlen(entry->d_name)); |
| - | if (my_stat(cur)) |
| + | } |
| + | fullname = concat_path_file(path, entry->d_name); |
| + | cur = my_stat(fullname, strrchr(fullname, '/') + 1); |
| + | if (!cur) |
| continue; | |
| cur->next = dn; | |
| dn = cur; | |
| @@ -621,7 +603,7 @@ static struct dnode **list_dir(char *path) | |
| /* now that we know how many files there are | |
| ** allocate memory for an array to hold dnode pointers | |
| */ | |
| - | if (nfiles < 1) |
| + | if (dn == NULL) |
| return (NULL); | |
| dnp = dnalloc(nfiles); | |
| for (i = 0, cur = dn; i < nfiles; i++) { | |
| @@ -635,10 +617,10 @@ static struct dnode **list_dir(char *path) | |
| /*----------------------------------------------------------------------*/ | |
| static int list_single(struct dnode *dn) | |
| { | |
| - | int i; |
| + | int i, column = 0; |
| #ifdef CONFIG_FEATURE_LS_USERNAME | |
| - | char scratch[BUFSIZ + 1]; |
| + | char scratch[16]; |
| #endif | |
| #ifdef CONFIG_FEATURE_LS_TIMESTAMPS | |
| char *filetime; | |
| @@ -649,7 +631,7 @@ static int list_single(struct dnode *dn) | |
| char append; | |
| #endif | |
| - | if (dn == NULL || dn->fullname == NULL) |
| + | if (dn->fullname == NULL) |
| return (0); | |
| #ifdef CONFIG_FEATURE_LS_TIMESTAMPS | |
| @@ -667,29 +649,20 @@ static int list_single(struct dnode *dn) | |
| for (i = 0; i <= 31; i++) { | |
| switch (list_fmt & (1 << i)) { | |
| case LIST_INO: | |
| - | printf("%7ld ", (long int) dn->dstat.st_ino); |
| - | column += 8; |
| + | column += printf("%7ld ", (long int) dn->dstat.st_ino); |
| break; | |
| case LIST_BLOCKS: | |
| - | #ifdef CONFIG_FEATURE_HUMAN_READABLE |
| - | printf("%6s ", make_human_readable_str(dn->dstat.st_blocks >> 1, |
| - | KILOBYTE, (ls_disp_hr == TRUE) ? 0 : KILOBYTE)); |
| - | #else |
| #if _FILE_OFFSET_BITS == 64 | |
| - | printf("%4lld ", dn->dstat.st_blocks >> 1); |
| + | column += printf("%4lld ", dn->dstat.st_blocks >> 1); |
| #else | |
| - | printf("%4ld ", dn->dstat.st_blocks >> 1); |
| - | #endif |
| + | column += printf("%4ld ", dn->dstat.st_blocks >> 1); |
| #endif | |
| - | column += 5; |
| break; | |
| case LIST_MODEBITS: | |
| - | printf("%-10s ", (char *) mode_string(dn->dstat.st_mode)); |
| - | column += 10; |
| + | column += printf("%-10s ", (char *) mode_string(dn->dstat.st_mode)); |
| break; | |
| case LIST_NLINKS: | |
| - | printf("%4ld ", (long) dn->dstat.st_nlink); |
| - | column += 10; |
| + | column += printf("%4ld ", (long) dn->dstat.st_nlink); |
| break; | |
| case LIST_ID_NAME: | |
| #ifdef CONFIG_FEATURE_LS_USERNAME | |
| @@ -701,29 +674,28 @@ static int list_single(struct dnode *dn) | |
| break; | |
| #endif | |
| case LIST_ID_NUMERIC: | |
| - | printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); |
| - | column += 17; |
| + | column += printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); |
| break; | |
| case LIST_SIZE: | |
| case LIST_DEV: | |
| if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { | |
| - | printf("%4d, %3d ", (int) MAJOR(dn->dstat.st_rdev), |
| + | column += printf("%4d, %3d ", (int) MAJOR(dn->dstat.st_rdev), |
| (int) MINOR(dn->dstat.st_rdev)); | |
| } else { | |
| #ifdef CONFIG_FEATURE_HUMAN_READABLE | |
| if (ls_disp_hr == TRUE) { | |
| - | printf("%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0)); |
| + | column += printf("%9s ", |
| + | make_human_readable_str(dn->dstat.st_size, 1, 0)); |
| } else | |
| #endif | |
| { | |
| #if _FILE_OFFSET_BITS == 64 | |
| - | printf("%9lld ", (long long) dn->dstat.st_size); |
| + | column += printf("%9lld ", (long long) dn->dstat.st_size); |
| #else | |
| - | printf("%9ld ", dn->dstat.st_size); |
| + | column += printf("%9ld ", dn->dstat.st_size); |
| #endif | |
| } | |
| } | |
| - | column += 10; |
| break; | |
| #ifdef CONFIG_FEATURE_LS_TIMESTAMPS | |
| case LIST_FULLTIME: | |
| @@ -752,13 +724,12 @@ static int list_single(struct dnode *dn) | |
| fgcolor(info.st_mode)); | |
| } | |
| #endif | |
| - | printf("%s", dn->name); |
| + | column += printf("%s", dn->name); |
| #ifdef CONFIG_FEATURE_LS_COLOR | |
| if (show_color) { | |
| printf("\033[0m"); | |
| } | |
| #endif | |
| - | column += strlen(dn->name); |
| break; | |
| case LIST_SYMLINK: | |
| if (S_ISLNK(dn->dstat.st_mode)) { | |
| @@ -778,13 +749,12 @@ static int list_single(struct dnode *dn) | |
| fgcolor(info.st_mode)); | |
| } | |
| #endif | |
| - | printf("%s", lpath); |
| + | column += printf("%s", lpath) + 4; |
| #ifdef CONFIG_FEATURE_LS_COLOR | |
| if (show_color) { | |
| printf("\033[0m"); | |
| } | |
| #endif | |
| - | column += strlen(lpath) + 4; |
| free(lpath); | |
| } | |
| } | |
| @@ -800,7 +770,7 @@ static int list_single(struct dnode *dn) | |
| } | |
| } | |
| - | return (0); |
| + | return column; |
| } | |
| /*----------------------------------------------------------------------*/ | |
| @@ -830,8 +800,6 @@ extern int ls_main(int argc, char **argv) | |
| #endif | |
| #ifdef CONFIG_FEATURE_AUTOWIDTH | |
| ioctl(fileno(stdout), TIOCGWINSZ, &win); | |
| - | if (win.ws_row > 4) |
| - | column_width = win.ws_row - 2; |
| if (win.ws_col > 0) | |
| terminal_width = win.ws_col - 1; | |
| #endif | |
| @@ -1025,10 +993,10 @@ extern int ls_main(int argc, char **argv) | |
| /* stuff the command line file names into an dnode array */ | |
| dn = NULL; | |
| for (oi = 0; oi < ac; oi++) { | |
| - | cur = (struct dnode *) xmalloc(sizeof(struct dnode)); |
| - | cur->fullname = xstrdup(av[oi]); |
| - | cur->name = cur->fullname; |
| - | if (my_stat(cur)) |
| + | char *fullname = xstrdup(av[oi]); |
| + | |
| + | cur = my_stat(fullname, fullname); |
| + | if (!cur) |
| continue; | |
| cur->next = dn; | |
| dn = cur; | |
| @@ -951,6 +951,44 @@ static int find_match(char *matchBuf, int *len_with_quotes) | |
| return command_mode; | |
| } | |
| + | /* |
| + | display by column original ideas from ls applet, |
| + | very optimize by my :) |
| + | */ |
| + | static void showfiles(char **matches, int nfiles) |
| + | { |
| + | int ncols, row; |
| + | int column_width = 0; |
| + | int nrows = nfiles; |
| + | |
| + | /* find the longest file name- use that as the column width */ |
| + | for (row = 0; row < nrows; row++) { |
| + | int l = strlen(matches[row]); |
| + | |
| + | if (column_width < l) |
| + | column_width = l; |
| + | } |
| + | column_width += 2; /* min space for columns */ |
| + | ncols = cmdedit_termw / column_width; |
| + | |
| + | if (ncols > 1) { |
| + | nrows /= ncols; |
| + | if(nfiles % ncols) |
| + | nrows++; /* round up fractionals */ |
| + | column_width = -column_width; /* for printf("%-Ns", ...); */ |
| + | } else { |
| + | ncols = 1; |
| + | } |
| + | for (row = 0; row < nrows; row++) { |
| + | int n = row; |
| + | int nc; |
| + | |
| + | for(nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) |
| + | printf("%*s", column_width, matches[n]); |
| + | printf("%s\n", matches[n]); |
| + | } |
| + | } |
| + | |
| static void input_tab(int *lastWasTab) | |
| { | |
| @@ -1078,29 +1116,11 @@ static void input_tab(int *lastWasTab) | |
| * just hit TAB again, print a list of all the | |
| * available choices... */ | |
| if (matches && num_matches > 0) { | |
| - | int i, col, l; |
| int sav_cursor = cursor; /* change goto_new_line() */ | |
| /* Go to the next line */ | |
| goto_new_line(); | |
| - | for (i = 0, col = 0; i < num_matches; i++) { |
| - | l = strlen(matches[i]); |
| - | if (l < 14) |
| - | l = 14; |
| - | printf("%-14s ", matches[i]); |
| - | col+=l; |
| - | if ((l += 2) > 16) |
| - | while (l % 16) { |
| - | putchar(' '); |
| - | l++; |
| - | } |
| - | if (col > (cmdedit_termw-l-l) && matches[i + 1] != NULL) { |
| - | putchar('\n'); |
| - | col = 0; |
| - | } |
| - | } |
| - | /* Go to the next line and rewrite */ |
| - | putchar('\n'); |
| + | showfiles(matches, num_matches); |
| redraw(0, len - sav_cursor); | |
| } | |
| } | |