RCS_ID_C "$Id: ls.c,v 3.2 1994/05/02 19:52:55 jraja Exp $";
/*
 * ls.c
 *
 * Author: ppessi <Pekka.Pessi@hut.fi>
 *
 * Copyright © 1991, 1993 Pekka Pessi. All rights reserved
 *
 * Last modified: Sat Feb 12 03:33:25 1994 ppessi
 *
 */

#include "ls_rev.h"

static const char version[] = VERSTAG " "
  "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  "Helsinki University of Technology, Finland.\n";

#include <stdlib.h>

#include "ls.h"

struct options options = { FALSE };

BPTR Stdin, Stdout, Stderr;
struct Library *UtilityBase = NULL;
APTR WinPtr;

static void resume_amiga_stdio(void)
{
  struct Process* me = (struct Process *)FindTask(NULL);
  me->pr_WindowPtr = WinPtr;
  if (UtilityBase)
    CloseLibrary(UtilityBase);
  UtilityBase = NULL;
}

static void startup_amiga_stdio(void)
{
  struct Process* me = (struct Process *)FindTask(NULL);
  Stdin = me -> pr_CIS;
  Stdout = me -> pr_COS;
  Stderr = (me -> pr_CES ? me -> pr_CES : Stdout);
  if (!UtilityBase) {
    UtilityBase = OpenLibrary("utility.library", 0);
    /* Remove requesters */
    WinPtr = me->pr_WindowPtr;
    me->pr_WindowPtr = (void *)-1L;
    atexit(resume_amiga_stdio);
  }
}

/****** utilities/ls ********************************************************

    NAME
        ls - list contents of directory

    VERSION
        $Id: ls.c,v 3.2 1994/05/02 19:52:55 jraja Exp $

    SYNOPSIS
        ls [ -acdfgilqrst1ACLFR ] name ...

    DESCRIPTION

        For each directory argument, ls lists the contents of the directory;
        for each file argument, ls repeats its name and any other informa-
        tion requested.  By default, the output is sorted alphabetically.
        When no argument is given, the current directory is listed.  When
        several arguments are given, the arguments are first sorted appropr-
        iately, but file arguments are processed before directories and
        their contents.

        There are a large number of options:

        -l   List in long format, giving mode, number of links, owner, size
             in bytes, and time of last modification for each file.  (See
             below.)  If the file is a symbolic link the pathname of the
             linked-to file is printed preceded by "->".

        -g   Include the group ownership of the file in a long output.

        -t   Sort by time modified (latest first) instead of by name.

        -a   List all entries; in the absence of this option, entries whose
             names begin with a period (".") or end with ".info" are not
             listed.

        -A   List all entries except entries whose names end with ".info".

        -s   Give size in blocks of each file.

        -d   If argument is a directory, list only its name; often used with
             -l to get the status of a directory.

        -L   If argument is a symbolic link, list the file or directory the
             link references rather than the link itself.

        -r   Reverse the order of sort to get reverse alphabetic or oldest
             first as appropriate.

        -i   For each file, print the key block number in the first column
             of the report.

        -f   Force each argument to be interpreted as a directory and list
             the name found in each slot.  This option turns off -l, -t, -s,
             and -r, and turns on -a; the order is the order in which
             entries appear in the directory.

        -F   Cause directories to be marked with a trailing `/', hard links
             sockets with a trailing `#' and symbolic links with a trailing
             `@'.

        -R   Recursively list subdirectories encountered.

        -p   Include relative pathname into the long listing.

        -1   Force one entry per line output format; this is the default
             when output is not interactive.

        -C   Force multi-column output; this is the default when output is
             interactive.

        -q   Force printing of non-graphic characters in file names as the
             character `?'; this is the default when output is interactive.

        The mode printed under the -l option contains 10 characters which
        are interpreted as follows: the first character is

        d       if the entry is a directory;
        r       if the entry is a root directory;
        l       if the entry is a symbolic link;
        D       if the entry is a hard link to a directory;
        p       if the entry is a pipe file;
        h       if the entry is a hard link to a file, or
        -       if the entry is a plain file.

        The next 9 characters are interpreted as three sets of access
        control bits. The first set refers to owner permissions; the next
        refers to permissions to others in the same user-group; and the last
        to all others. Within each set the three characters indicate
        permission respectively to read, to write, or to execute the file as
        a program. For a directory, `write' and `execute' permissions are
        meaningless. The permissions are indicated as follows:

        r       if the file is readable;
        w       if the file is writable;
        x       if the file is executable;
        -       if the indicated permission is not granted.

        The write-permission character is given as a D if the file is
        deleteable but not writeable. It is given as a 'W' if the file is
        writeable but not deleteable. The group-execute permission character
        is given as s if the file has the set-group-id bit set; likewise the
        user-execute permission character is given as s if the file has the
        set-user-id bit set.

        The last character of the mode (normally `x' or `-') is 't' or 'T'
        (as sticky in Unix systems) if the pure bit of the mode is on. If
        the script bit is on, the last character is 's' or 'S'. The
        protection bits `h' and `a' are not printed.

        When the sizes of the files in a directory are listed, a total count
        of blocks (not including indirect blocks) is printed.

    FILES
        AmiTCP:db/passwd to get user id's for `ls -l'.
        AmiTCP:db/group to get group id's for `ls -g'.

    BUGS
        The option setting based on whether the output is interactive is
        undesirable as "ls -s" is much different than "ls -s > t:file".

        The printed protection flags are inadequate for Amiga DOS. The root
        directory flags are garbage. There are problems when printing soft
        links.

        There are too many options.

    AUTHOR
        Pekka Pessi, <Pekka.Pessi@hut.fi>. 
        ls is part of the AmiTCP/IP package.
****************************************************************************
*/

int
main(int argc, char **argv)
{
  struct ExAllList *listing = NULL;
  char *path = malloc(MAXPATHLEN);
  char *option;
  int optionerror = 0;
  int optind = 0;

  startup_amiga_stdio();

  while (++optind < argc && (argv[optind])[0] == '-') {
    option = argv[optind] + 1;
    while (*option)
      switch(*option++) {
      case 'l':			/* long */
	options.longformat = TRUE;
	break;
      case 'g':
	options.group = TRUE;
	break;
      case 't': 
	options.sort_time = TRUE;
	break;
      case 'a':
	options.all = TRUE;
	break;
      case 'A':
	options.dotted = TRUE;
	break;
      case 's':
	options.kilos = TRUE;
	break;
      case 'd':
	options.dir = TRUE;
	break;
      case 'r':
	options.reverse = TRUE;
	break;
      case 'i':
	options.inode = TRUE;
	break;
      case 'f':
	options.fast = TRUE;
	break;
      case 'F':
	options.filetype = TRUE;
	break;
      case 'L':
	options.symbolic = TRUE;
	break;
      case 'R':
	options.recursion = TRUE;
	break;
      case 'q':
	options.nongraph = TRUE;
	break;
      case 'C':
	options.multicolumn = TRUE;
	if (options.singlecolumn) optionerror++;
	break;
      case '1':			/* one */
	options.singlecolumn = TRUE;
	if (options.multicolumn) optionerror++;
	break;
      case 'p':
	options.pathname = TRUE;
	break;
      case '?':
      default:
	optionerror++;
      }
    if (optionerror != 0) {
      FPrintf(Stderr, "Usage: %s [-lgtasdrifFLRC1q] [patterns...]\n", argv[0]);
      exit(RETURN_ERROR);
    }
  }

  if (!path) 
    exit(RETURN_ERROR);
  path[0] = '\0';
  
  if (IsInteractive(Stdout))
    options.nongraph = TRUE;
  if (optind >= argc) {
    listing = listpatterns(1, &path, options);
  } else {
    listing = listpatterns(argc - optind, argv + optind, options);
  }	

  if (listing)
    doprint(path, listing, options);

  exit(RETURN_OK);
  /*NOTREACHED*/
}
