Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 21 Jun 1998 16:07:59 -0500 (CDT)
From:      Joel Ray Holveck <detlev!joelh@mail.camalott.com>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/7011: Improvements to ls to help Emacs users; patch included
Message-ID:  <199806212107.QAA25952@detlev.UUCP>

next in thread | raw e-mail | index | archive | help

>Number:         7011
>Category:       bin
>Synopsis:       Improvements to ls to help Emacs users; patch included
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jun 21 14:10:01 PDT 1998
>Last-Modified:
>Originator:     Joel Ray Holveck
>Organization:
None
>Release:        FreeBSD 3.0-CURRENT i386
>Environment:

FreeBSD-current, cvsup'd late 20Jun98.  GNU Emacs 20.2.2.  

>Description:

Emacs's editing mode, dired, will ls individual files when it creates
changes.  However, our current implementation of ls may use different
column widths for different sets of files being ls'd.  This means that
if a single dired directory listing includes data from multiple
invocations of ls, the columns may not align properly.

This problem should also exist under any other directory utility which
directly displays the output of ls, and will display data obtained
from multiple invocations with different filesets at the same time.

>How-To-Repeat:

Launch Emacs.  Press: C-x C-f ~ RET

Dired will launch and displays a directory listing of the home
directory.  A portion of a sample follows:

  -rwxr-xr-x   1 joelh  joelh     3863 May 11 23:20 .bashrc
  -rw-r--r--   1 joelh  joelh    32126 Jun 21 14:10 .emacs
  -rw-r--r--   1 joelh  joelh      209 Jan  8 12:34 .emacs.bmk
  -rw-r--r--   1 joelh  joelh        0 Mar  4 02:45 .emacs_args
  -rw-------   1 joelh  joelh     4217 Jun 17 00:24 .fetchmailrc

Using C-n and C-p, navigate to an item that uses less than the maximum
width of any column (eg, has a size an order of magnitude smaller than
another).  (I am using .emacs.bmk as an example.)  Press M
(dired-do-chmod).  Press u+r (which is probably a nop in chmod, but
will cause the file selected to refresh by itself).  The directory
will now have skewed columns:

  -rwxr-xr-x   1 joelh  joelh     3863 May 11 23:20 .bashrc
  -rw-r--r--   1 joelh  joelh    32126 Jun 21 14:10 .emacs
  -rw-r--r--  1 joelh  joelh  209 Jan  8 12:34 .emacs.bmk
  -rw-r--r--   1 joelh  joelh        0 Mar  4 02:45 .emacs_args
  -rw-------   1 joelh  joelh     4217 Jun 17 00:24 .fetchmailrc

>Fix:
	
I propose a change to ls which will allow minimum column widths to be
set in the environment.  A runtime environment variable, LS_COLWIDTHS
is added.  This is a colon-delimited list of minimum column widths for
each variable-width column, in order of display by 'ls -lois'.  For
example, by default, 'ls -l' may display:

total 321
-rw-r--r--  1 joelh  bin    7435 Jun 21 13:45 cmp.o
-rwxr-xr-x  1 joelh  bin  238385 Jun 21 14:42 ls
-rw-r--r--  1 joelh  bin    4352 Jun 21 14:42 ls.1.gz
-rw-r--r--  1 joelh  bin   21182 Jun 21 14:42 ls.o
-rw-r--r--  1 joelh  bin   16457 Jun 21 13:45 print.o
-rw-r--r--  1 joelh  bin    9814 Jun 21 13:45 stat_flags.o
-rw-r--r--  1 joelh  bin   11508 Jun 21 13:45 util.o

However, with LS_COLWIDTHS set to 6:4:2:8:8:1:7:0 (the affected fields
for a simple -l listing are block count, user, group, and size),
'ls -l' in the same directory will display:

total 321
-rw-r--r--   1 joelh     bin          7435 Jun 21 13:45 cmp.o
-rwxr-xr-x   1 joelh     bin        238385 Jun 21 14:42 ls
-rw-r--r--   1 joelh     bin          4352 Jun 21 14:42 ls.1.gz
-rw-r--r--   1 joelh     bin         21182 Jun 21 14:42 ls.o
-rw-r--r--   1 joelh     bin         16457 Jun 21 13:45 print.o
-rw-r--r--   1 joelh     bin          9814 Jun 21 13:45 stat_flags.o
-rw-r--r--   1 joelh     bin         11508 Jun 21 13:45 util.o

By setting LS_COLWIDTHS to a reasonable value, all invocations of ls
will use the same column widths, thereby effectively allowing a
repeatable output format under normal conditions.  (The problem will
still manifest as before if the column widths specified in
LS_COLWIDTHS are insufficient to display the requested listing, since
the columns output will still expand to meet the needs of the
listing.)

If additional output columns are added in the future, it is
recommended to append column width specifiers to LS_COLWIDTHS rather
than adding them in display order, to maintain backward compatibility.

Attached are the diffs to ls.c and ls.1 to implement the recommended
change.

Happy hacking,
joelh

*** ls.c-orig	Sun Jun 21 13:54:31 1998
--- ls.c	Sun Jun 21 14:42:40 1998
***************
*** 69,74 ****
--- 69,75 ----
  static void	 display __P((FTSENT *, FTSENT *));
  static int	 mastercmp __P((const FTSENT **, const FTSENT **));
  static void	 traverse __P((int, char **, int));
+ static u_quad_t	 makenines __P((u_long));
  
  static void (*printfcn) __P((DISPLAY *));
  static int (*sortfcn) __P((const FTSENT *, const FTSENT *));
***************
*** 396,401 ****
--- 397,403 ----
  	u_quad_t maxsize;
  	u_long btotal, maxblock, maxinode, maxlen, maxnlink;
  	int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser;
+ 	char* initmax;
  	int entries, needstats;
  	char *user, *group, *flags, buf[20];	/* 32 bits == 10 digits */
  
***************
*** 411,421 ****
  
  	needstats = f_inode || f_longform || f_size;
  	flen = 0;
! 	btotal = maxblock = maxinode = maxlen = maxnlink = 0;
  	bcfile = 0;
- 	maxuser = maxgroup = maxflags = 0;
  	flags = NULL;
- 	maxsize = 0;
  	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
  		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
  			warnx("%s: %s",
--- 413,441 ----
  
  	needstats = f_inode || f_longform || f_size;
  	flen = 0;
! 	btotal = 0;
! 	initmax = getenv("LS_COLWIDTHS");
! 	/* This sscanf matches the order of ls -lios. */
! 	if (initmax != NULL) {
! 		if (sscanf(initmax,
! 			   " %lu : %lu : %lu : %i : %i : %i : %qu : %lu ",
! 			   &maxinode, &maxblock, &maxnlink, &maxuser,
! 			   &maxgroup, &maxflags, &maxsize, &maxlen)
! 		    == 8) {
! 			maxinode = makenines(maxinode);
! 			maxblock = makenines(maxblock);
! 			maxnlink = makenines(maxnlink);
! 			maxsize = makenines(maxsize);
! 		} else {
! 			fputs("ls: bad LS_COLWIDTHS\n", stderr);
! 			initmax = NULL;
! 		}
! 	}
! 	if (initmax == NULL)
! 		maxblock = maxinode = maxlen = maxnlink =
! 			maxuser = maxgroup = maxflags = maxsize = 0;
  	bcfile = 0;
  	flags = NULL;
  	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
  		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
  			warnx("%s: %s",
***************
*** 560,563 ****
--- 580,603 ----
  			return (-1);
  	}
  	return (sortfcn(*a, *b));
+ }
+ 
+ /*
+  * Makenines() returns (10**n)-1.  This is useful for converting a width
+  * into a number that wide in decimal.
+  */
+ static u_quad_t
+ makenines(n)
+ 	u_long n;
+ {
+ 	u_long i;
+ 	u_quad_t reg;
+ 
+ 	reg = 1;
+ 	/* Use a loop instead of pow(), since all values of n are small. */
+ 	for (i = 0; i < n; i++)
+ 		reg *= 10;
+ 	reg--;
+ 
+ 	return reg;
  }
*** ls.1-orig	Sun Jun 21 14:35:08 1998
--- ls.1	Sun Jun 21 14:41:42 1998
***************
*** 373,378 ****
--- 373,385 ----
  See
  .Xr environ 7
  for more information.
+ .It Ev LS_COLWIDTHS
+ If this variable is set, it is considered to be a
+ colon-delimited list of minimum column widths (possibly
+ zero).  The columns are, in order: inode, block count,
+ number of links, user name, group name, flags, file size,
+ file name.  (This corresponds to the order of the relevant
+ columns in output.)
  .El
  .Sh COMPATIBILITY
  The group field is now automatically included in the long listing for
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199806212107.QAA25952>