?? cfls.c
字號:
len += 4;
}
}
else
len += 1;
}
if (indicator_style != none)
{
if (filetype == S_IFREG)
{
if (indicator_style == all
&& (f->stats.st_mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
len += 1;
}
else if (filetype & S_IFDIR
#ifdef S_IFLNK
|| filetype == S_IFLNK
#endif
#ifdef S_IFIFO
|| filetype == S_IFIFO
#endif
#ifdef S_IFSOCK
|| filetype == S_IFSOCK
#endif
) len += 1;
}
#ifdef PCDOS
if(format == many_per_line)
{
if(filetype == S_IFDIR)
{
len += 2;
if(indicator_style != none) --len;
}
}
#endif
return len;
}
void
print_many_per_line ()
{
int filesno; /* Index into files. */
int row; /* Current row. */
int max_name_length; /* Length of longest file name + frills. */
int name_length; /* Length of each file name + frills. */
int pos; /* Current character column. */
int cols; /* Number of files across. */
int rows; /* Maximum number of files down. */
/* Compute the maximum file name length. */
max_name_length = 0;
for (filesno = 0; filesno < files_index; filesno++)
{
name_length = length_of_file_name_and_frills (files + filesno);
if (name_length > max_name_length)
max_name_length = name_length;
}
/* Allow at least two spaces between names. */
max_name_length += 2;
/* Calculate the maximum number of columns that will fit. */
cols = line_length / max_name_length;
if (cols == 0)
cols = 1;
/* Calculate the number of rows that will be in each column except possibly
for a short column on the right. */
rows = files_index / cols + (files_index % cols != 0);
/* Recalculate columns based on rows. */
cols = files_index / rows + (files_index % rows != 0);
for (row = 0; row < rows; row++)
{
filesno = row;
pos = 0;
/* Print the next row. */
while (1)
{
print_file_name_and_frills (files + filesno);
name_length = length_of_file_name_and_frills (files + filesno);
filesno += rows;
if (filesno >= files_index)
break;
indent (pos + name_length, pos + max_name_length);
pos += max_name_length;
}
putchar ('\n');
}
}
void
print_horizontal ()
{
int filesno;
int max_name_length;
int name_length;
int cols;
int pos;
/* Compute the maximum file name length. */
max_name_length = 0;
for (filesno = 0; filesno < files_index; filesno++)
{
name_length = length_of_file_name_and_frills (files + filesno);
if (name_length > max_name_length)
max_name_length = name_length;
}
/* Allow two spaces between names. */
max_name_length += 2;
cols = line_length / max_name_length;
if (cols == 0)
cols = 1;
pos = 0;
name_length = 0;
for (filesno = 0; filesno < files_index; filesno++)
{
if (filesno != 0)
{
if (filesno % cols == 0)
{
putchar ('\n');
pos = 0;
}
else
{
indent (pos + name_length, pos + max_name_length);
pos += max_name_length;
}
}
print_file_name_and_frills (files + filesno);
name_length = length_of_file_name_and_frills (files + filesno);
}
putchar ('\n');
}
void
print_with_commas ()
{
int filesno;
int pos, old_pos;
pos = 0;
for (filesno = 0; filesno < files_index; filesno++)
{
old_pos = pos;
pos += length_of_file_name_and_frills (files + filesno);
if (filesno + 1 < files_index)
pos += 2; /* For the comma and space */
if (old_pos != 0 && pos >= line_length)
{
putchar ('\n');
pos -= old_pos;
}
print_file_name_and_frills (files + filesno);
if (filesno + 1 < files_index)
{
putchar (',');
putchar (' ');
}
}
putchar ('\n');
}
#ifndef PCDOS
struct userid
{
unsigned short uid;
char *name;
struct userid *next;
};
struct userid *user_alist;
/* Translate `uid' to a login name, with cache. */
char *
getuser (uid)
unsigned short uid;
{
register struct userid *tail;
struct passwd *pwent;
char usernum_string[20];
for (tail = user_alist; tail; tail = tail->next)
if (tail->uid == uid)
return tail->name;
pwent = getpwuid (uid);
tail = (struct userid *) xmalloc (sizeof (struct userid));
tail->uid = uid;
tail->next = user_alist;
if (pwent == NULL)
{
sprintf (usernum_string, "%u", (unsigned short) uid);
tail->name = copystring (usernum_string);
}
else
tail->name = copystring (pwent->pw_name);
user_alist = tail;
return tail->name;
}
/* We use the same struct as for userids. */
struct userid *group_alist;
/* Translate `gid' to a group name, with cache. */
char *
getgroup (gid)
unsigned short gid;
{
register struct userid *tail;
struct group *grent;
char groupnum_string[20];
for (tail = group_alist; tail; tail = tail->next)
if (tail->uid == gid)
return tail->name;
grent = getgrgid (gid);
tail = (struct userid *) xmalloc (sizeof (struct userid));
tail->uid = gid;
tail->next = group_alist;
if (grent == NULL)
{
sprintf (groupnum_string, "%u", (unsigned int) gid);
tail->name = copystring (groupnum_string);
}
else
tail->name = copystring (grent->gr_name);
group_alist = tail;
return tail->name;
}
#endif
/* Assuming cursor is at position `from', indent up to position `to'. */
void
indent (from, to)
int from, to;
{
while (from < to)
{
if (to / tabsize > from / tabsize)
{
putchar ('\t');
from += tabsize - from % tabsize;
}
else
{
putchar (' ');
from++;
}
}
}
/* Low level subroutines of general use,
not specifically related to the task of listing a directory. */
char *
xrealloc (obj, size)
void *obj;
int size;
{
char *val = realloc (obj, size);
if (!val)
error (1, 0, "virtual memory exhausted");
return val;
}
char *
xmalloc (size)
int size;
{
char *val = malloc (size);
if (!val)
error (1, 0, "virtual memory exhausted");
return val;
}
/* Return a newly allocated copy of `string'. */
char *
copystring (string)
char *string;
{
return strcpy ((char *) xmalloc (strlen (string) + 1), string);
}
/* Put `dirname/name' into `dest', handling `.' and `/' properly. */
void
attach (dest, dirname, name)
char *dest, *dirname, *name;
{
char *dirnamep = dirname;
/* Copy dirname if it is not ".". */
if (dirname[0] != '.' || dirname[1] != 0)
{
while (*dirnamep)
*dest++ = *dirnamep++;
/* Add '/' if `dirname' doesn't already end with it. */
if (dirnamep > dirname && (dirnamep[-1] != '/'
#ifdef PCDOS
&& dirnamep[-1] != ':'
#endif
))
*dest++ = '/';
}
while (*name)
*dest++ = *name++;
*dest = 0;
}
/* Check for a globbing pattern in an explicit argument, the shell may
have passed it along, always for PCDOS. */
int
if_pattern(name)
register char *name;
{
register char ch;
while (ch = *name++)
if (ch == '*' || ch == '?' || ch == '[')
return 1;
return 0;
}
#ifdef PCDOS
void lose_backslashes(char *path)
{
while(*path)
{
if(*path == '\\') *path = '/';
++path;
}
}
#endif
void
usage ()
{
fprintf (stdout, "\
Usage: ls [-abdgiklnpqrstxABCFNQRSUX1] [path...]\n");
fprintf (stdout, "\n\
Switch-------------------Meaning\n\
a, +all List all files.\n\
b, +escape Quote nongraphic characters.\n\
d, +directory List directory name, not contents.\n\
g, Ignored for Unix compatibility.\n\
i, +inode Print index number of each file.\n\
k, +kilobytes Print file sizes in kilobyte blocks.\n\
l, +format=long Print in long format.\n\
m, +format=commas List files horizontally, separated by commas.\n\
p Put '/' after each directory, if not multi-col.\n\
r, +reverse Sort in reverse order.\n\
s, +size Print the size of each file in blocks allocated.\n\
t, +sort=time Sort directory contents by timestamp.\n\
x, +format=across Multi-column, sorted horizontally.\n\
A, +almost-all List all files except for '.' and '..'.\n\
B, +ignore-backups Do not list files that end with '~'.\n\
C, +format=vertical Multi-column, sorted vertically.\n\
F, +classify Tag the file type of each file.\n\
N, +literal Do not quote file names.\n\
Q, +quote-name Enclose file names in double quotes.\n\
R, +recursive List the contents of directories recursively.\n\
S, +sort=size Sort directory contents by file size.\n\
U, +sort=none Do not sort directory contents.\n\
X, +sort=extension Sort directory contents by file extension.\n\
1, +format=single-column List one file per line.\n\
w, +width cols Assume screen width to be 'cols' wide.\n\
T. +tabsize cols Assume that each tabstop is 'cols' wide.\n\
I, +ignore pattern Do not list files that match 'pattern'.\n");
exit (1);
}
/* Getopt for GNU.
Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef __STDC__
#define CONST const
#else
#define CONST
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of `argv' so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = 0;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
_POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable _POSIX_OPTION_ORDER, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Describe the long-named options requested by the application.
_GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
element containing a name which is zero.
The field `has_arg' is 1 if the option takes an argument,
2 if it takes an optional argument. */
CONST struct option *_getopt_long_options;
int _getopt_long_only = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -