/* zoo.c -- includes main() function */
/*
Copyright (C) 1986 Rahul Dhesi -- All rights reserved
*/
#include "options.h"
#include <stdio.h>
#include "various.h"

#include "zoo.h"
#include "zoofns.h"

#include "errors.i"
#include "zoomem.h"

#ifdef DEBUG
int verbose = 0;
#endif

char *out_buf_adr;      /* points to memory allocated for output buffer(s) */
char *in_buf_adr;       /* points to memory allocated for input buffer */

/* static declarations */
int quiet = 0;             /* whether to be quiet */
int next_arg = FIRST_ARG; /* filenames start at this position */
int arg_count;          /* count of arguments supplied to program */
char **arg_vector;      /* vector of arguments supplied to program */

/* Suppress loading of some Microsoft C library routines. */
#ifdef NDEBUG
#ifndef PORTABLE
_nullcheck() {}         /* prevent loading of Microsoft's null ptr check */
#endif
#endif

#ifndef PORTABLE
_setenvp() {}           /* prevent loading of Microsoft's _setenvp */
#endif

main(argc,argv)
register int argc;
register char **argv;
{
   char *zooname;          /* synonym for argv[2] -- to make life easier */
#ifndef OOZ
   static char incorrect_args[] = "Incorrect number of arguments.\n";
   int filecount;          /* how many filespecs supplied */
#endif /* OOZ */

#ifdef OOZ
      static char usage1[] = "Public domain fast Ooz extractor, INTERNAL USE TEST VERSION by Rahul Dhesi\n";
      static char usage2[] = "Usage:  ooz archive[.zoo] [file] ...\n";

#else
/* else not OOZ */
      static char usage[] = "Usage:  zoo {acDelLPTuUvx}[acdEfnMNoOpPquz1:/] archive file (\"zoo h\" for help)\n";
      static char nov_usage[] = 
          "\nNovice usage:  zoo -cmd archive[.zoo] file...  where -cmd is one of these:\n";
      char *option;

      static char nov_cmds[] = 
         /* ADD=0EXT=5    MOV=14TES=20PRI=26 DEL=33  LIS=41UPD=47  FRE=55   COMMENT=64 */
           "-add -extract -move -test -print -delete -list -update -freshen -comment\n";

#ifdef NOENUM
#define NONE   -1
#define ADD    0
#define EXTRACT 5
#define MOVE   14
#define TEST   20
#define PRINT  26
#define DELETE 33
#define LIST   41
#define UPDATE 47
#define FRESHEN   55
#define COMMENT   64

int cmd = NONE;

#else
   enum choice {
      NONE=-1, ADD=0, EXTRACT=5, MOVE=14, TEST=20, PRINT=26, 
      DELETE=33, LIST=41, UPDATE=47, FRESHEN=55, COMMENT=64
   };
   enum choice cmd = NONE;          /* assume no Novice command */
#endif

#endif /* end of not OOZ */

#ifdef SETBUF
/* set stdout to unbuffered */
setbuf (stdout, NULL);
#endif

   arg_count = argc;
   arg_vector = argv;
   zooname = argv[FIRST_ARG-1];     /* points to name or archive */

#ifdef OOZ
   if (argc < 2) {
      putstr (usage1);
      putstr (usage2);
      exit (1);
   }
#else
/* else not OOZ */
   if (argc < 2)
      goto show_usage;
   filecount = argc - 3;
   option = strdup(argv[1]);

#ifdef DEBUG
   if (*option == ':') {         /* for debugging output */
      verbose++;
      option++;                  /* hide the $ from other functions */
   }
#endif

   if (*option == 'h' || *option == 'H')
      goto bigusage;
   if (*option == '-') {

#ifdef NOENUM
      cmd = index (nov_cmds, strlwr(option));
#else
      cmd = (enum choice) index (nov_cmds, strlwr(option));
#endif

      if (strlen(option) < 2 || cmd == NONE)
         goto show_usage;
      if (  ((cmd == ADD || cmd == MOVE || cmd == FRESHEN || 
                  cmd == UPDATE || cmd == DELETE) && argc < 4) ||
            ((cmd == EXTRACT || cmd == TEST || cmd == LIST ||
                     cmd == PRINT || cmd == COMMENT) && argc < 3)) {
         fprintf (stderr, incorrect_args);
         goto show_usage;
      }
   } else {
      if    (strchr("aDuU",*option) && argc < 4 ||
             strchr("cexlL",*option) && argc < 3 ||
             strchr("TP",*option)   && argc != 3)  {
         fprintf (stderr, incorrect_args);
         goto show_usage;
      }
   }
#endif /* end of not OOZ */

#ifndef OOZ
   /* if not doing a list and no extension in archive name, add default 
   extension */
   if (cmd != LIST && strchr("lvL", *option) == NULL &&
         strchr(nameptr (zooname), EXT_CH) == NULL)
      zooname = newcat (zooname, EXT_DFLT);
#endif

#ifndef PORTABLE
#ifndef OOZ
/* only need to ensure integrity of created archive */
   break_off();   /* break = off -- specific to MSDOS */
#endif
#endif

/* 
Here we allocate a large block of memory for the duration of the program.
lzc() and lzd() will use half of it each.  Routine getfile() will use all
of it. 
*/
/* fudge factor to avoid off-by-one errors */
#define  FUDGE    10

/*                          fudge/2           fudge/2
**             [______________||________________|]
**               output buffer    input buffer
*/

   out_buf_adr = emalloc (OUT_BUF_SIZE + IN_BUF_SIZE + FUDGE);

   /* input buffer is in top of allocated block */
   in_buf_adr = out_buf_adr + OUT_BUF_SIZE + (FUDGE/2);

#ifdef OOZ
zooext(zooname, "\0");     /* just extract -- no fancy stuff   */
exit (0);                  /* and exit normally                */
#else
/* else not OOZ -- parse command line and invoke a routine */
   if (cmd != NONE) {
      switch (cmd) {

         case ADD:      zooadd (zooname, filecount, &argv[3], "aP"); break;
         case FRESHEN:  zooadd (zooname, filecount, &argv[3], "auP"); break;
         case UPDATE:   zooadd (zooname, filecount, &argv[3], "aunP"); break;
         case MOVE:     zooadd (zooname, filecount, &argv[3], "aMP"); break;

         case EXTRACT:  zooext (zooname, "x"); break;
         case TEST:     zooext (zooname, "xNd"); break;
         case PRINT:    zooext (zooname, "xp"); break;

         case DELETE:   zoodel (zooname, "DP",1); break;
         case LIST:     zoolist (&argv[2], "v", argc-2); break;
         case COMMENT:  comment (zooname, "c"); break;
         default: goto show_usage;
      }
   } else
      switch (*option) {
         case 'a': 
         case 'u':
         case 'T':   
            zooadd (zooname, filecount, &argv[3], option); break;
         case 'D':
            zoodel (zooname, option, 1); break;
         case 'U':
            zoodel (zooname, option, 0); break;
         case 'v':
         case 'l': 
            zoolist(&argv[2], option, 1); break;
         case 'L': 
            zoolist(&argv[2], option, argc-2); break;
         case 'e':
         case 'x': 
            zooext(zooname, option); break;
         case 'P':
            zoopack (zooname, option); break;
         case 'c':
            comment (zooname, option); break;
         default:
            fprintf (stderr, usage); exit (1); break;
      }
exit (0);      /* don't fall through */

show_usage:
   fprintf (stderr, "%s%s%s", usage, nov_usage, nov_cmds);
   exit (1);

bigusage:

printf ("Zoo archiver, version 1.41 (GENERIC, 1987/02/07)\n");
printf("(C) Copyright 1986, 1987 Rahul Dhesi -- Noncommercial use permitted\n");

printf (usage);
printf ("\nChoose a command from within {} and zero or more modifiers from within []\n");

printf ("E.g.:  `zoo x bin/backups' will extract all files from bin/backups.zoo\n\n");

printf (" Commands in {} mean:         |Modifiers in [] mean:\n");

printf ("  a     add files             | a     show archive name(s) in listing\n");
printf ("  c     update comments       | c     add/list comments\n");
printf ("  D     delete stored files   | d     extract/list deleted files too\n");
printf ("  e,x   extract files         | dd    extract/list only deleted files\n");
printf ("  l,v,L list filenames        | E     erase backup after packing\n");
printf ("  P     pack archive          | f     fast add (no compression) or list\n");
printf ("  T     fix archive datestamp | M     move when adding (erase original)\n");
printf ("  u     add only newer files  | n     add only files not already in archive\n");
printf ("  U     undelete stored files | N     send extracted data to Neverland\n");
printf (" -----------------------------  O,oo  don't ask \"Overwrite?\"\n");
printf ("  q     be quiet                p     pipe extracted data to standard output\n");
printf ("  :     don't store dir names   /,//  extract full pathnames\n");

#ifdef PORTABLE
printf ("  P     pack after adding       @n    start extract/list at position n\n");
/* nothing */
#else
printf ("  z     add/extract Z format    @n    start extract/list at position n\n");
#endif /* ndef PORTABLE */


printf (nov_usage);
printf (nov_cmds);
#endif /* end of not OOZ */

/* NOTE:  if allowed to fall through and return without an exit() statement,
   it was printing garbage--corrupted stack?  Why--bug in Microsoft C? */
exit (1);
}
