blob: 5848eaa1131db8e248b2fca2ae6a4bd828a68ec5 [file] [log] [blame]
/* ls command handling
Copyright (C) 1999 Jakub Jelinek
2001 Ben Collins
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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#include <sys/types.h>
#include <silo.h>
#include <stringops.h>
typedef int FILE;
#include <linux/types.h>
#include <ext2fs/ext2_fs.h>
#include <ext2fs/ext2fs.h>
int ls_opt = 0;
static int do_ls_cmp (struct silo_inode *a, struct silo_inode *b)
{
int ret;
ret = strcmp ((char *)a->name, (char *)b->name);
if (ret) {
if (!strcmp ((char *)a->name, ".")) return -1;
if (!strcmp ((char *)b->name, ".")) return 1;
if (!strcmp ((char *)a->name, "..")) return -1;
if (!strcmp ((char *)b->name, "..")) return 1;
}
if (ls_opt & LSOPT_T) {
if (a->mtime < b->mtime)
ret = 1;
else if (a->mtime > b->mtime)
ret = -1;
}
if (ls_opt & LSOPT_R)
ret = -ret;
return ret;
}
static void sortit (struct silo_inode **b, int n, struct silo_inode **t)
{
struct silo_inode **tmp;
struct silo_inode **b1, **b2;
int n1, n2;
if (n <= 1)
return;
n1 = n / 2;
n2 = n - n1;
b1 = b;
b2 = b + n1;
sortit (b1, n1, t);
sortit (b2, n2, t);
tmp = t;
while (n1 > 0 && n2 > 0) {
if (do_ls_cmp (*b1, *b2) <= 0) {
*tmp = *b1;
b1++;
--n1;
} else {
*tmp = *b2;
b2++;
--n2;
}
tmp++;
}
if (n1 > 0)
memcpy (tmp, b1, n1 * sizeof (*b));
memcpy (b, t, (n - n2) * sizeof (*b));
}
static void ls_rwx (unsigned int bits, char *chars)
{
chars[0] = (bits & LINUX_S_IRUSR) ? 'r' : '-';
chars[1] = (bits & LINUX_S_IWUSR) ? 'w' : '-';
chars[2] = (bits & LINUX_S_IXUSR) ? 'x' : '-';
}
static void ls_modestring (unsigned int mode, char *chars)
{
if (LINUX_S_ISBLK (mode)) chars[0] = 'b';
else if (LINUX_S_ISCHR (mode)) chars[0] = 'c';
else if (LINUX_S_ISDIR (mode)) chars[0] = 'd';
else if (LINUX_S_ISREG (mode)) chars[0] = '-';
else if (LINUX_S_ISFIFO (mode)) chars[0] = 'p';
else if (LINUX_S_ISLNK (mode)) chars[0] = 'l';
else if (LINUX_S_ISSOCK (mode)) chars[0] = 's';
ls_rwx ((mode & 0700) << 0, chars+1);
ls_rwx ((mode & 0070) << 3, chars+4);
ls_rwx ((mode & 0007) << 6, chars+7);
if (mode & LINUX_S_ISUID) {
if (chars[3] != 'x')
chars[3] = 'S';
else
chars[3] = 's';
}
if (mode & LINUX_S_ISGID) {
if (chars[6] != 'x')
chars[6] = 'S';
else
chars[6] = 's';
}
if (mode & LINUX_S_ISVTX) {
if (chars[9] != 'x')
chars[9] = 'T';
else
chars[9] = 't';
}
}
void print_number (unsigned int num, int pad, char padc)
{
int len;
unsigned int i;
for (len = 1, i = num; i >= 10; len++) i /= 10;
if (pad > 0) { /* Pad left */
while (len < pad) { putchar (padc); len++; }
printf ("%d", num);
} else {
printf ("%d", num);
while (len < -pad) { putchar (padc); len++; }
}
}
int do_ls (unsigned char *buf, int *tab_ambiguous)
{
int i, n, j;
struct silo_inode *sino;
struct silo_inode **array, **p;
n = 0;
for (sino = (struct silo_inode *) buf; sino->inolen;
sino = (struct silo_inode *) (((char *)sino) + sino->inolen))
n++;
if (!n) return 0;
array = p = (struct silo_inode **)sino;
for (sino = (struct silo_inode *) buf, i = 0; i < n;
sino = (struct silo_inode *) (((char *)sino) + sino->inolen), i++)
*p++ = sino;
sortit (array, n, array + n);
if (tab_ambiguous == NULL && ls_opt & LSOPT_L) {
char mode[11];
char *q;
unsigned int mtime;
int day, hour, min, month, year;
static char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static unsigned short m_yday[] = {
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
for (i = 0; i < n; i++) {
ls_modestring (array[i]->mode, mode);
mode[10] = 0;
printf ("%s ", mode);
print_number (array[i]->uid, -8, ' ');
printf (" ");
print_number (array[i]->gid, -8, ' ');
printf (" ");
print_number (array[i]->size, 8, ' ');
printf (" ");
mtime = array[i]->mtime;
/* Following code taken from glibc */
day = mtime / (60 * 60 * 24);
hour = mtime % (60 * 60 * 24);
hour /= 60;
min = hour % 60;
hour /= 60;
year = 1970;
#define ISLEAP(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
while (day < 0 || day >= (ISLEAP (year) ? 366 : 365)) {
/* Guess a corrected year, assuming 365 days per year. */
long int yg = year + day / 365 - (day % 365 < 0);
/* Adjust DAYS and Y to match the guessed year. */
day -= ((yg - year) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (year - 1));
year = yg;
}
if (!ISLEAP(year) && day >= 59) day++;
for (month = 11; day < m_yday[month]; month--);
day -= m_yday[month] - 1;
printf ("%s ", months[month]);
print_number (day, 2, ' ');
putchar (' ');
print_number (hour, 2, '0');
putchar (':');
print_number (min, 2, '0');
printf (" %d %s", year, array[i]->name);
if (LINUX_S_ISLNK (array[i]->mode)) {
q = strchr ((char *)array[i]->name, 0) + 1;
if (*q) printf (" -> %s", q);
}
printf ("\n");
}
} else {
if (tab_ambiguous == NULL || *tab_ambiguous) {
/* Either this is a normal ls, or we have an ambiguous
* completion. */
if (tab_ambiguous != NULL)
printf("\n");
for (i = 0; i < n; i++) {
printf ("%s", array[i]->name);
j = 19 - strlen((char *)array[i]->name);
if ((i & 3) == 3 || i == n - 1)
printf ("\n");
else
do printf (" "); while (j-- > 0);
}
return 1;
} else if (tab_ambiguous != NULL) {
/* A possible completion. If we cannot add anything to the
* command line, then set tab_ambiguous, so the next go round
* can do a listing. */
char *index = strrchr(cbuff, '/') + 1;
int len = strlen(index);
if (!*index) {
*tab_ambiguous = 1;
} else if (n == 1) {
/* One entry, just complete to that. */
while (array[0]->name[len]) {
index[len] = array[0]->name[len];
index[len + 1] = 0;
prom_puts(index + len, 1);
len++;
}
index[len] = (LINUX_S_ISDIR (array[0]->mode)) ? '/' : ' ';
index[len + 1] = 0;
prom_puts(index + len, 1);
} else {
/* Ok, complete as much as is common between all the
* entries. */
int common = 1, orig = len;
while (common && array[0]->name[len]) {
for (i = 1; i < n && common; i++)
if (array[i]->name[len] != array[0]->name[len])
common = 0;
if (common) {
index[len] = array[0]->name[len];
index[len + 1] = 0;
prom_puts(index + len, 1);
len++;
}
}
if (orig == len)
*tab_ambiguous = 1;
}
}
}
return 0;
}