/**************************************************************/
  /*                                                            */
  /*      UNIX 1 / WS 92/93       Gruppe  ux803                 */
  /*      4. Uebung - Aufgabe 3 - ls.c                          */
  /*                                                            */
  /*      Vorname     Name        Matrikelnr.                   */
  /*     ---------   -------     -------------                  */
  /*      Dietmar     Dierks        125761                      */
  /*      Roman       Czyborra      127221                      */
  /*      Torsten     Buller        117894                      */
  /*      Gerasimos   Paliatsaras   140956                      */
  /*                                                            */
  /**************************************************************/


#include <sys/stat.h>
static int isdir(name) /* Directory ? */
     char *name;
{
  static struct stat st;
  if (lstat(name, &st) == -1) return 0;
  return (S_ISDIR(st.st_mode));
}

static void printtype(mode) /* Dateityp */
     mode_t mode;
{
  switch (mode & _IFMT) {
  case _IFREG:  putchar('-'); break;
  case _IFDIR:  putchar('d'); break;
  case _IFCHR:  putchar('c'); break;
  case _IFBLK:  putchar('b'); break;
  case _IFIFO:  putchar('p'); break;
  case _IFSOCK: putchar('s'); break;
  case _IFLNK:  putchar('l'); break;
  default:      putchar('?'); /* sollte eigentlich nicht auftreten */
  }
}

static void printmode(mode) /* Zugriffsrechte */
     mode_t mode;
{
  putchar (mode & S_IRUSR ? 'r' : '-');
  putchar (mode & S_IWUSR ? 'w' : '-');
  if (mode & S_ISUID) putchar (mode & S_IXUSR ? 's' : 'S');
                else  putchar (mode & S_IXUSR ? 'x' : '-');
  putchar (mode & S_IRGRP ? 'r' : '-');
  putchar (mode & S_IWGRP ? 'w' : '-');
  if (mode & S_ISGID) putchar (mode & S_IXGRP ? 's' : 'S');
                else  putchar (mode & S_IXGRP ? 'x' : '-');
  putchar (mode & S_IROTH ? 'r' : '-');
  putchar (mode & S_IWOTH ? 'w' : '-');
  if (mode & S_ISVTX) putchar (mode & S_IXOTH ? 't' : 'T');
                else  putchar (mode & S_IXOTH ? 'x' : '-');
}

#include <pwd.h>
static void printuid(uid)
     uid_t uid;
{
  struct passwd *pwd;
  pwd = getpwuid (uid);
  printf("%-9s", pwd->pw_name);
}

#include <time.h>
#define FIELD 14
static void printtime(mtime)
     time_t mtime;
{
  time_t systime;                 /* aktuelle Zeit */
  struct tm *m;
  char str[FIELD];

  time(&systime);
  m = localtime (&mtime);         /* Umwandlung in lesbares Format */
  if (systime - mtime > 15811200) /* Aenderungsdatum vor mehr als 6 Monaten */
  strftime(str, FIELD, "%b %e %Y ",   m);
  else strftime(str, FIELD, "%b %e %H:%M", m);
  printf (str);
} 

#include <sys/param.h>
static void showentry(name)
     char *name;
{
  struct stat st;

  if (lstat(name, &st) == -1) { perror(name); return; }
  printtype(st.st_mode);
  printmode(st.st_mode);
  printf("%3d ",st.st_nlink);
  printuid(st.st_uid);          /* Filebesitzer */
  if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) /* Device */
    printf("%3d,%4d ", major(st.st_rdev), minor(st.st_rdev));
  else
    printf("%8ld ", st.st_size); /* Filegroesse */
  printtime(st.st_mtime);       /* letzte Aenderung ausgeben */
  if (S_ISLNK(st.st_mode)) {    /* Ist File ein Link? */
    char buf[MAXPATHLEN];       /* Speicher reservieren fuer Link */
    int cnt;                    /* tatsaechliche Zeichenanzahl des Links */
    cnt = readlink(name, buf, MAXPATHLEN);
    if (cnt == -1) { perror ("readlink"); exit (-1); }
    buf[cnt]='\0';              /* String muss nullterminierend sein */
    printf(" %s -> %s\n", name, buf);  /* Link ausgeben */
  }
  else printf(" %s\n", name);    /* Dateinamen ausgeben */
}

#include <dirent.h>
static long getsize(dir)
     DIR *dir;
{
  struct dirent *next;
  struct stat st;
  long res;
  res = 0;
  while (next = readdir(dir)) {
    lstat(next->d_name, &st);
    res += st.st_blocks;
  }
  rewinddir(dir);
  return (res >> 1); /* Korrektur: stat() liefert die doppelte Blockzahl */
}

void printdir ()
{
  DIR *dir; /* zu untersuchendes Directory */
  struct dirent *next;
  dir = opendir(".");
  if (!dir) { perror ("opendir"); exit (-1); }
  printf("total %ld\n", getsize(dir));
  while (next = readdir(dir))
    showentry(next->d_name);
  closedir(dir);
}

#include <fcntl.h>
#include "parser.h"
void do_ls(cmd)
     struct kommando *cmd;
{
  int i, wd;

  if (cmd->num_tok1 > 1) /* wurden Argumente angegeben ? */
    for (i = 1; i < cmd -> num_tok1; i++)
      if (isdir(cmd->token_1[i])) {
	wd = open (".", O_RDONLY);  /* merke cwd in inode table */
	if (wd == -1) { perror ("open . "); exit (-1); }
	printf ("%s:\n", cmd->token_1[i]);
        if (chdir (cmd->token_1[i]) == -1)
	  { perror ("chdir"); close (wd); return; }
	printdir ();
	fchdir (wd); /* altes cwd wiederherstellen */
	close (wd);
      }
      else
	showentry(cmd->token_1[i]);
  else
    printdir ();
}