/* cmd-inventory.c: file inventories
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2002, 2003  Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "config-options.h"
#include "po/gettext.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/cmd/main.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/char/pika-escaping-utils.h"
#include "hackerlab/os/errno-to-string.h"
#include "libarch/project-tree.h"
#include "libarch/invent.h"
#include "commands/cmd.h"
#include "commands/inventory.h"
#include "commands/version.h"



static t_uchar * usage = N_("[options] [dir]*");

#define OPTS(OP) \
  OP (opt_help_msg, "h", "help", 0, \
      N_("display help")) \
  OP (opt_long_help, "H", 0, 0, \
      N_("Display a verbose help message and exit.")) \
  OP (opt_version, "V", "version", 0, \
      N_("display version info\n")) \
  OP (opt_source, "s", "source", 0, \
      N_("list source files")) \
  OP (opt_precious, "p", "precious", 0, \
      N_("list precious files")) \
  OP (opt_backups, "b", "backups", 0, \
      N_("list backup files")) \
  OP (opt_junk, "j", "junk", 0, \
      N_("list junk files")) \
  OP (opt_unrecognized, "u", "unrecognized", 0, \
      N_("list unrecognized files")) \
  OP (opt_trees, "t", "trees", 0, \
      N_("list roots of nested trees\n")) \
  OP (opt_directories, "d", "directories", 0, \
      N_("list only directories")) \
  OP (opt_files, "f", "files", 0, \
      N_("list only non-directories")) \
  OP (opt_both, "B", "both", 0, \
      N_("list both dirs and files")) \
  OP (opt_kind, 0, "kind", 0, \
      N_("indicate file kinds\n")) \
  OP (opt_all, 0, "all", 0, \
      N_("include arch control files")) \
  OP (opt_nested, 0, "nested", 0, \
      N_("include nested trees")) \
  OP (opt_no_recursion, 0, "no-recursion", 0, \
      N_("do not list content of directory\n")) \
  OP (opt_ids, 0, "ids", 0, \
      N_("list with ids (source files only)")) \
  OP (opt_untagged, 0, "untagged", 0, \
      N_("include files that are missing ids\n")) \
  OP (opt_explicit, 0, "explicit", 0, \
      N_("use explicit file ids")) \
  OP (opt_implicit, 0, "implicit", 0, \
      N_("permit implicit file ids")) \
  OP (opt_tagline, 0, "tagline", 0, \
      N_("permit tagline file ids")) \
  OP (opt_names, 0, "names", 0, \
      N_("use name-based file ids")) \
  OP (opt_unescaped, 0, "unescaped", 0, \
      N_("show filenames in unescaped form"))


t_uchar arch_cmd_inventory_help[] = N_("inventory a source tree\n"
                                     "With no arguments, print a human-readable inventory report.\n"
                                     "\n"
                                     "With category options (--source etc) limit the report to just\n"
                                     "those files.  With no other options, the report includes all\n"
                                     "sections and files.\n"
                                     "\n"
                                     "The options -d, -f, and -b cancel each other.\n"
                                     "\n"
                                     "The options --nested and --no-recursion cancel each other.\n"
                                     "\n"
                                     "If a directory is precious, junk, or unrecognized, only the\n"
                                     "directory name itself is printed -- its contents are not\n"
                                     "searched.\n");

enum options
{
  OPTS (OPT_ENUM)
};

static struct opt_desc opts[] =
{
  OPTS (OPT_DESC)
    {-1, 0, 0, 0, 0}
};


/* __STDC__ prototypes for static functions */
static void inventory_printer (void * closure, invent_callback_data_t const * const data);



static int show_dirs = 0;
static int show_files = 1;
static int show_kind = 0;
static int show_ids;

static int n_categories = 0;

int
arch_cmd_inventory (t_uchar * program_name, int argc, char * argv[])
{
  int o;
  struct opt_parsed * option;
  struct arch_inventory_options inv_options;
  int escape_classes = arch_escape_classes;

  option = 0;
  mem_set0 ((t_uchar *)&inv_options, sizeof (inv_options));

  while (1)
    {
      o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv,
                        program_name, usage, libarch_version_string, arch_cmd_inventory_help,
                        opt_help_msg, opt_long_help, opt_version);
      if (o == opt_none)
        break;
      switch (o)
        {
        default:
          safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
          panic ("internal error parsing arguments");

        usage_error:
          opt_usage (2, argv[0], program_name, usage, 1);
          exit (1);

        /* bogus_arg: */
          safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
          goto usage_error;

        case opt_source:
          inv_options.categories |= arch_inventory_source;
          break;

        case opt_precious:
          inv_options.categories |= arch_inventory_precious;
          break;

        case opt_backups:
          inv_options.categories |= arch_inventory_backup;
          break;

        case opt_junk:
          inv_options.categories |= arch_inventory_junk;
          break;

        case opt_unrecognized:
          inv_options.categories |= arch_inventory_unrecognized;
          break;

        case opt_trees:
          inv_options.categories |= arch_inventory_tree;
          break;

        case opt_no_recursion:
          inv_options.no_recursion = 1;
          inv_options.nested = 0;
          break;

        case opt_directories:
          show_dirs = 1;
          show_files = 0;
          break;

        case opt_files:
          show_dirs = 0;
          show_files = 1;
          break;

        case opt_both:
          show_dirs = 1;
          show_files = 1;
          break;

        case opt_kind:
          show_kind = 1;
          break;

        case opt_all:
          inv_options.include_excluded = 1;
          break;

        case opt_nested:
          inv_options.nested = 1;
          inv_options.no_recursion = 0;
          break;

        case opt_ids:
          inv_options.want_ids = 1;
          show_ids = 1;
          break;

        case opt_untagged:
          inv_options.treat_unrecognized_source_as_source = 1;
          break;

        case opt_explicit:
          inv_options.override_method = 1;
          inv_options.method = arch_explicit_id_tagging;
          break;

        case opt_implicit:
          inv_options.override_method = 1;
          inv_options.method = arch_implicit_id_tagging;
          break;

        case opt_tagline:
          inv_options.override_method = 1;
          inv_options.method = arch_tagline_id_tagging;
          break;

        case opt_names:
          inv_options.override_method = 1;
          inv_options.method = arch_names_id_tagging;
          break;

	case opt_unescaped:
          escape_classes = 0;
          break;
        }
    }

  lim_free (lim_use_must_malloc, option);

  n_categories = 0;
  if (inv_options.categories & arch_inventory_source)
    ++n_categories;

  if (inv_options.categories & arch_inventory_precious)
    ++n_categories;

  if (inv_options.categories & arch_inventory_backup)
    ++n_categories;

  if (inv_options.categories & arch_inventory_junk)
    ++n_categories;

  if (inv_options.categories & arch_inventory_tree)
    ++n_categories;

  if (inv_options.categories & arch_inventory_unrecognized)
    ++n_categories;

  if (!n_categories)
    {
      n_categories = 6;
      inv_options.categories = arch_inventory_source | arch_inventory_precious | arch_inventory_backup | arch_inventory_tree | arch_inventory_unrecognized;
    }

  if (argc == 1)
    {
      argv[1] = ".";
      ++argc;
    }

  {
    int x;
    int errn;
    int re_error;

    for (x = 1; x < argc; ++x)
      {
        arch_project_tree_t * tree;
        char * bad_file;
        errn = 0;
        re_error = 0;

        if ( vu_access(&errn, argv[x], X_OK | F_OK ) == -1) 
          {
            safe_printfmt (2, "inventory: Cannot access directory %s\n%s\n", argv[x], errno_to_string(errn));
            exit (2);
          }
        tree = arch_project_tree_new_ext (talloc_context, argv[x], 1, 0);
        arch_get_inventory_naming_conventions (&inv_options, tree);

        bad_file = 0;
        
        arch_inventory_traversal_path (&inv_options, tree, argv[x], inventory_printer, &escape_classes);
        arch_free_inventory_naming_conventions (&inv_options);
        arch_project_tree_delete (tree);
      }
  }
  return 0;
}



static void
inventory_printer (void * closure, invent_callback_data_t const * const data)
{
  t_uchar * path = data->path;

  if ((data->category != arch_inventory_tree) && !show_dirs && S_ISDIR (data->stat_buf.st_mode))
    return;

  if (!show_files && !S_ISDIR (data->stat_buf.st_mode))
    return;

  if (n_categories > 1)
    {
      t_uchar * quest = (data->has_source_name ? "?" : " ");

      switch (data->category)
        {
        case arch_inventory_source:
          safe_printfmt (1, "S  ");
          break;
        case arch_inventory_precious:
          safe_printfmt (1, "P%s ", quest);
          break;
        case arch_inventory_backup:
          safe_printfmt (1, "B%s ", quest);
          break;
        case arch_inventory_junk:
          safe_printfmt (1, "J%s ", quest);
          break;
        case arch_inventory_tree:
          safe_printfmt (1, "T%s ", quest);
          break;
        case arch_inventory_unrecognized:
          safe_printfmt (1, "U%s ", quest);
          break;
        case arch_inventory_excludes:
          break;
        }
    }

  if (show_kind)
    {
      if (S_ISDIR (data->stat_buf.st_mode))
        safe_printfmt (1, "d ");
      else if (S_ISLNK (data->stat_buf.st_mode))
        safe_printfmt (1, "> ");
      else
        safe_printfmt (1, "r ");
    }

  if (path[0] == '.' && path[1] == '/')
    path += 2;

  {
    t_uchar * item;
    item = pika_save_escape_iso8859_1 (0, 0, *(int *)closure, path);

    safe_printfmt (1, "%s%s%s\n", item, (show_ids ? "\t" : ""), (show_ids ? (data->id ? (char *)data->id : "???") : ""));

    lim_free (0, item);
  }
}



/* tag: Tom Lord Wed May 14 10:52:12 2003 (srcfind.c)
 */


syntax highlighted by Code2HTML, v. 0.9.1