/* Copyright (c) 1979 Regents of the University of California */
* ls - list file or directory
* Modified by Bill Joy UCB May/August 1977
* This version of ls is designed for graphic terminals and to
* list directories with lots of files in them compactly.
* It supports three variants for listings:
* 3) Old one per line format.
* Columnar output is the default.
* If, however, the standard output is not a teletype, the default
* With columnar output, the items are sorted down the columns.
* We use columns only for a directory we are interpreting.
* Thus, in particular, we do not use columns for
* This version of ls also prints non-printing characters as '?' if
* the standard output is a teletype.
* Flags relating to these and other new features are:
* -m force stream output.
* -1 force one entry per line, e.g. to a teletype
* -q force non-printings to be '?'s, e.g. to a file
* -c force columnar output, e.g. into a file
* -n like -l, but user/group id's in decimal rather than
* looking in /etc/passwd to save time
int aflg
, dflg
, lflg
, sflg
, tflg
, uflg
, iflg
, fflg
, gflg
, cflg
;
int Aflg
, nflg
, qflg
, across
;
struct lbuf
*flist
[NFILES
];
struct lbuf
**lastp
= flist
;
struct lbuf
**firstp
= flist
;
register struct lbuf
*ep
, **ep1
;
register struct lbuf
**slastp
;
year
= lb
.lmtime
- 6L*30L*24L*60L*60L; /* 6 months ago */
qflg
= gtty(1, buff
) == 0;
* If the standard output is not a teletype,
* then we default to one-per-line format
* otherwise decide between stream and
* columnar based on our name.
for (cp
= argv
[0]; cp
[0] && cp
[1]; cp
++)
* Name ends in l => stream
* ... if doesn't end in l or s ==> columns sorted across
if (--argc
> 0 && *argv
[1] == '-') {
while (*++*argv
) switch (**argv
) {
* c - force columnar output
* m - force stream output
* q - force ?'s in output
* 1 - force 1/line in output
* n - don't look in password file
for (i
=0; i
< argc
; i
++) {
if ((ep
= gstat(*++argv
, 1))==NULL
)
qsort(firstp
, lastp
- firstp
, sizeof *lastp
, compar
);
for (epp
=firstp
; epp
<slastp
; epp
++) {
if (ep
->ltype
=='d' && dflg
==0 || fflg
) {
printf("\n%s:\n", ep
->ln
.namep
);
qsort(slastp
,lastp
- slastp
,sizeof *lastp
,compar
);
printf("total %D", tblocks
);
register struct lbuf
**slp
, **lp
;
int ncols
, nrows
, row
, col
;
register struct lbuf
**ep
;
if (ncols
== 1 || cflg
== 0) {
for (ep
= slp
; ep
< lp
; ep
++)
for (ep
= slp
; ep
< lp
; ep
++)
nrows
= (lp
- slp
- 1) / ncols
+ 1;
for (row
= 0; row
< nrows
; row
++) {
col
= row
== 0 && statreq
;
for (; col
< ncols
; col
++) {
ep
= slp
+ (nrows
* col
) + row
;
outcol
= (outcol
+ 8) &~ 7;
if (qflg
&& (c
< ' ' || c
>= 0177))
if (outcol
+ colwidth
+ 2 > 80) {
if ((outcol
/ colwidth
+ 2) * colwidth
> 80) {
} while (outcol
% colwidth
);
while((c
=fgetc(pwdf
)) != '\n') {
int m1
[] = { 1, S_IREAD
>>0, 'r', '-' };
int m2
[] = { 1, S_IWRITE
>>0, 'w', '-' };
int m3
[] = { 2, S_ISUID
, 's', S_IEXEC
>>0, 'x', '-' };
int m4
[] = { 1, S_IREAD
>>3, 'r', '-' };
int m5
[] = { 1, S_IWRITE
>>3, 'w', '-' };
int m6
[] = { 2, S_ISGID
, 's', S_IEXEC
>>3, 'x', '-' };
int m7
[] = { 1, S_IREAD
>>6, 'r', '-' };
int m8
[] = { 1, S_IWRITE
>>6, 'w', '-' };
int m9
[] = { 2, S_ISVTX
, 't', S_IEXEC
>>6, 'x', '-' };
int *m
[] = { m1
, m2
, m3
, m4
, m5
, m6
, m7
, m8
, m9
};
for (mp
= &m
[0]; mp
< &m
[sizeof(m
)/sizeof(m
[0])];)
while (--n
>=0 && (flags
&*pairp
++)==0)
static struct direct dentry
;
register struct lbuf
*ep
;
if ((dirf
= fopen(dir
, "r")) == NULL
) {
printf("%s unreadable\n", dir
);
if (fread(&dentry
, sizeof(dentry
), 1, dirf
) != 1)
aflg
==0 && dentry
.d_name
[0]=='.' && (
|| dentry
.d_name
[1]=='.' && dentry
.d_name
[2]=='\0'))
ep
= gstat(makename(dir
, dentry
.d_name
), 0);
ep
->ln
.lname
[j
] = dentry
.d_name
[j
];
register struct lbuf
*rep
;
rep
= (struct lbuf
*)malloc(sizeof(struct lbuf
));
fprintf(stderr
, "ls: out of memory\n");
if (lastp
>= &flist
[NFILES
]) {
fprintf(stderr
, "ls: too many files\n");
if (stat(file
, &statb
)<0) {
printf("%s not found\n", file
);
rep
->lnum
= statb
.st_ino
;
rep
->lsize
= statb
.st_size
;
switch(statb
.st_mode
&S_IFMT
) {
rep
->lsize
= statb
.st_rdev
;
rep
->lsize
= statb
.st_rdev
;
rep
->lflags
= statb
.st_mode
& ~S_IFMT
;
rep
->luid
= statb
.st_uid
;
rep
->lgid
= statb
.st_gid
;
rep
->lnl
= statb
.st_nlink
;
rep
->lmtime
= statb
.st_atime
;
rep
->lmtime
= statb
.st_ctime
;
rep
->lmtime
= statb
.st_mtime
;
tblocks
+= nblock(statb
.st_size
);
struct lbuf
**pp1
, **pp2
;
register struct lbuf
*p1
, *p2
;
if (p1
->lflags
&ISARG
&& p1
->ltype
=='d') {
if (!(p2
->lflags
&ISARG
&& p2
->ltype
=='d'))
if (p2
->lflags
&ISARG
&& p2
->ltype
=='d')
if(p2
->lmtime
== p1
->lmtime
)
if(p2
->lmtime
> p1
->lmtime
)
return(rflg
* strcmp(p1
->lflags
&ISARG
? p1
->ln
.namep
: p1
->ln
.lname
,
p2
->lflags
&ISARG
? p2
->ln
.namep
: p2
->ln
.lname
));
struct { char dminor
, dmajor
;};
printf("%D ", nblock(p
->lsize
));
printf("%4D ", nblock(p
->lsize
));
if (nflg
== 0 && getname(t
, tbuf
)==0)
if (p
->ltype
=='b' || p
->ltype
=='c')
printf("%3d,%3d", major((int)p
->lsize
), minor((int)p
->lsize
));
printf("%7ld", p
->lsize
);
printf(" %-7.7s %-4.4s ", cp
+4, cp
+20); else
printf(" %-12.12s ", cp
+4);
printf("%s", p
->ln
.namep
);
printf("%.14s", p
->ln
.lname
);
/* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
/* This version of printf is compatible with the Version 7 C
* printf. The differences are only minor except that this
* printf assumes it is to print through pputchar. Version 7
* printf is more general (and is much larger) and includes
* provisions for floating point.
#define MAXOCT 11 /* Maximum octal digits in a long */
#define MAXINT 32767 /* largest normal length positive integer */
#define BIG 1000000000 /* largest power of 10 less than an unsigned long */
#define MAXDIGS 10 /* number of digits in BIG */
static int width
, sign
, fill
;
int length
,mask1
,nbits
,n
;
/* process format string first */
while ((fcode
= *fmt
++)!='%') {
/* ordinary (non-%) character */
/* length modifier: -1 for h, 1 for l, 0 for none */
/* check for a leading - sign */
/* a '0' may follow the - sign */
/* this is the requested fill character */
/* Now comes a digit string which may be a '*' */
while (*fmt
>='0' && *fmt
<='9')
width
= width
* 10 + (*fmt
++ - '0');
/* maybe a decimal point followed by more digits (or '*') */
while (*fmt
>='0' && *fmt
<='9')
prec
= prec
* 10 + (*fmt
++ - '0');
* At this point, "sign" is nonzero if there was
* a sign, "fill" is 0 if there was a leading
* zero and 1 otherwise, "width" and "prec"
* contain numbers corresponding to the digit
* strings before and after the decimal point,
* respectively, and "fmt" addresses the next
* character after the whole mess. If there was
* no decimal point, "prec" will be -1.
* At exit from the following switch, we will
* emit the characters starting at "bptr" and
* ending at "ptr"-1, unless fcode is '\0'.
switch (fcode
= *fmt
++) {
/* process characters and strings first */
buf
[0] = va_arg(ap
, int);
bptr
= va_arg(ap
,char *);
for (n
=0; *bptr
++ && n
< prec
; n
++) ;
num
= (unsigned)va_arg(ap
,int);
/* shift and mask for speed */
if (((int) num
& mask1
) < 10)
*--bptr
= ((int) num
& mask1
) + 060;
*--bptr
= ((int) num
& mask1
) + 0127;
while (num
= (num
>> nbits
) & mask2
);
if (!sign
&& fill
<= 0) {
fcode
= fcode
+ 'a' - 'A';
if (n
= (fcode
!= 'u' && num
< 0))
/* now convert to digits */
bptr
= b_dconv(num
, buf
);
/* not a control character,
/* b_dconv converts the unsigned long integer "value" to
* printable decimal and places it in "buffer", right-justified.
* The value returned is the address of the first non-zero character,
* or the address of the last character if all are zero.
* The result is NOT null terminated, and is MAXDIGS characters long,
* starting at buffer[1] (to allow for insertion of a sign).
* This program assumes it is running on 2's complement machine
* with reasonable overflow treatment.
/* zero is a special case */
/* develop the leading digit of the value in "n" */
value
-= BIG
; /* will eventually underflow */
while ((lval
= value
- BIG
) >= 0) {
/* stash it in buffer[1] to allow for a sign */
* Now develop the rest of the digits. Since speed counts here,
* we do it in two loops. The first gets "value" down until it
* is no larger than MAXINT. The second one uses integer divides
* rather than long divides to speed it up.
*--bp
= (int)(value
% 10) + '0';
/* cannot lose precision */
*--bp
= (svalue
% 10) + '0';
/* fill in intermediate zeroes if needed */
* This program sends string "s" to pputchar. The character after
* the end of "s" is given by "send". This allows the size of the
* field to be computed; it is stored in "alen". "width" contains the
* user specified length. If width<alen, the width will be taken to
* be alen. "sign" is zero if the string is to be right-justified
* in the field, nonzero if it is to be left-justified. "fill" is
* 0 if the string is to be padded with '0', positive if it is to be
* padded with ' ', and negative if an initial '-' should appear before
* any padding in right-justification (to avoid printing "-3" as
* "000-3" where "-0003" was intended).
cfill
= fill
>0? ' ': '0';
/* we may want to print a leading '-' before anything */
if (*s
== '-' && fill
< 0) {
/* emit any leading pad characters */
/* emit the string itself */
/* emit trailing pad characters */