#include <stdlib.h>
#include <libraries/xpkarchive.h>
#include <exec/libraries.h>

struct Library *XpkArchiveBase;

#define BUFSIZE 4096L

char buffer[BUFSIZE];

void __regargs __chkabort(void) {}           /* disable SAS ^C handling */
long __asm chunkfunc(register __a1 struct XpkProgress *prog);

struct Hook chunkhook = {{0},chunkfunc};

char *path;
BPTR lock;

USHORT SplitGeneration(char *filename)
/*
 * NOTE: This function modifies the filename !!!
 */
{
   USHORT gen=0;

   if(filename=strrchr(filename,'\\')) {
      if(sscanf(filename+1,"%hu",&gen)!=1) {
         fprintf(stderr,"Invalid filename with generation\n",filename);
      } else {
         *filename=0;
      }
   }
   return gen;
}
char *BaseName(char *filename)
{
   char *p;

   if(p=strchr(filename,':')) filename=p+1;
   while(*filename=='/') filename++;
   return filename;
}
void Usage(char *name)
{
   fprintf(stderr,"Usage: %s [-m Method] [-d Dir] {adlnrux} <archive> [<file[\\gen]>] ...\n",name);
   exit(EXIT_FAILURE);
}
void Quit(char *err)
{
   if(XpkArchiveBase) CloseLibrary(XpkArchiveBase);
   if(err) fprintf(stderr,"%s\n",err);
   if(path) CurrentDir(lock);

   exit(err?EXIT_FAILURE:EXIT_SUCCESS);
}


#define ReadOpt(var) if(argv[optindex][2]) var=argv[optindex]+2; else var=argv[++optindex];

main(argc,argv)
int argc;
char *argv[];
{
   XarHandle *arc,*arc2;
   int optindex;
   char *method=NULL;

   for(optindex=1;optindex<argc && argv[optindex][0]=='-';optindex++) {
      switch(argv[optindex][1]) {

         case 'm':
         case 'M': ReadOpt(method);
                   break;

         case 'd':
         case 'D': ReadOpt(path);
                   break;

         default:
         case 'h':
         case 'H': Usage(argv[0]);
                   break;

      }
   }

   if(argc-optindex<2) Usage(argv[0]);

   if(path && !(lock=Lock(path,SHARED_LOCK))) {
      path=NULL;
      Quit("Cannot change directory");
   }
   if(path) lock=CurrentDir(lock);

   if(!(XpkArchiveBase=OpenLibrary("xpkarctest.library",0L)))
      Quit("Cannot open xpkarctest.library\n");


   switch(argv[optindex++][0]) {

      case 'a': /* Add a file */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeAppend,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot create archive");
               if(method==NULL) {
                  method=XarGetType(arc)->DefaultID;
                  if(!method[0]) {
                     method="SHRI";
                  }
               }

               for(;optindex<argc;optindex++) {

                  if(!XarAddFile(XAR_InName,argv[optindex],
                                 XAR_FileName,BaseName(argv[optindex]),
                                 XAR_Generation,SplitGeneration(argv[optindex]),
                                 XAR_Archive,arc,
                                 XAR_PackMethod,method,
                                 XAR_ProgressHook,&chunkhook,TAG_DONE))
                  {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;


      case 'l': /* List files */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");

               {

                  ULONG sum1=0,sum2=0;
                  float ratio;
                  XarLock *lock;
                  struct XarFileData *data;
                  struct XarPackMode mode;

                  puts("Original Packed Ratio  Date     Time   D Gen Mode Name\n"
                       "-------- ------ ---- -------- -------- - --- ---- ----------");
                  for(lock=XarGetLock(arc);lock;lock=XarNextLock(lock)) {
                     ULONG compsize;

                     data=XarGetFileData(lock);
                     compsize=XarGetFileSize(lock);
                     sum1+=data->Filesize;
                     sum2+=compsize;

                     if(data->Filesize==0) ratio=0; else ratio=100.0-100*(float)compsize/data->Filesize;
                     XarGetPackMode(lock,&mode);

                     printf("%8lu %6lu %4.1f %2d.%02d.%02d %2d:%02d:%02d %c %3d %4s %s\n",
                             data->Filesize,compsize,ratio,data->Time.Day,data->Time.Month,
                             data->Time.Year,data->Time.Hour,data->Time.Min,data->Time.Sec,
                             XarIsDeletedFD(data)?'D':' ',
                             data->Generation,mode.ID,XarGetFileName(lock));

                     if(XarGetFileNote(lock)) puts(XarGetFileNote(lock));
                  }
                  puts("-------- ------ ----");
                  if(sum1==0) ratio=0; else ratio=100.0-100*(float)sum2/sum1;
                  printf("%8lu %6lu %4.1f\n",sum1,sum2,ratio);
               }

               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;


      case 'x': /* Extract file */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               for(;optindex<argc;optindex++) {

                  if(XarExtractFile(XAR_OutName,argv[optindex],
                                 XAR_FileName,BaseName(argv[optindex]),
                                 XAR_Generation,SplitGeneration(argv[optindex]),
                                 XAR_Archive,arc,
                                 XAR_ProgressHook,&chunkhook,TAG_DONE))
                  {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;

      case 'd': /* Delete file */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               for(;optindex<argc;optindex++) {

                  XarLock *lock;

                  if(lock=XarFindFile(XAR_FileName,BaseName(argv[optindex]),
                                      XAR_Generation,SplitGeneration(argv[optindex]),
                                      XAR_Archive,arc,
                                      TAG_DONE))
                  {
                     if(XarDeleteFile(lock))
                     printf("Error: %s\n",XarWhy(arc,0));
                  } else {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;
      case 'u': /* Undelete file */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               for(;optindex<argc;optindex++) {

                  XarLock *lock;

                  if(lock=XarFindFile(XAR_FileName,BaseName(argv[optindex]),
                                      XAR_Generation,SplitGeneration(argv[optindex]),
                                      XAR_Archive,arc,
                                      TAG_DONE))
                  {
                     if(XarUndeleteFile(lock))
                     printf("Error: %s\n",XarWhy(arc,0));
                  } else {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;
      case 'r': /* Rename file */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               for(;optindex<argc;optindex+=2) {

                  if(XarRenameFile(XAR_FileName,BaseName(argv[optindex]),
                                  XAR_Generation,SplitGeneration(argv[optindex]),
                                  XAR_Archive,arc,
                                  XAR_NewName,argv[optindex+1],
                                  XAR_NewGeneration,SplitGeneration(argv[optindex+1]),
                                  TAG_DONE))
                  {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;
      case 'c': /* Set comment */

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               for(;optindex<argc;optindex+=2) {

                  if(XarSetFileNote(XAR_FileName,BaseName(argv[optindex]),
                                  XAR_Generation,SplitGeneration(argv[optindex]),
                                  XAR_Archive,arc,
                                  XAR_FileNote,argv[optindex+1],
                                  TAG_DONE))
                  {
                     printf("Error: %s\n",XarWhy(arc,0));
                  }
               }
               if(XarCloseArchive(arc)) Quit("Error closing archive");
               break;

      case 'p': /* pack archive */

               if(argc-optindex<2) Usage(argv[0]);

               if(!(arc=XarOpenArchive(XAR_ArchiveName,argv[optindex++],
                                       XAR_ArchiveMode,XAR_ModeOldArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) Quit("Cannot open archive");


               if(!(arc2=XarOpenArchive(XAR_ArchiveName,argv[optindex],
                                        XAR_ArchiveMode,XAR_ModeNewArchive,
                                       XAR_ShowDirs,TRUE,
                                       TAG_DONE))) {
                  XarCloseArchive(arc);
                  Quit("Cannot open archive");
               }

               if(XarPackArchive(arc,arc2)) {
                  printf("Error: %s\n",XarWhy(arc,0));
               }

               if(XarCloseArchive(arc2)) Quit("Error closing archive");
               if(XarCloseArchive(arc)) Quit("Error closing archive");

               break;

      case 'e': /* Try to expung lib */
               XpkArchiveBase->lib_Flags|=LIBF_DELEXP;
               break;

      default: Quit("Unknown command");
   }
   Quit(NULL);
}
long __asm chunkfunc(register __a1 struct XpkProgress *prog)
{
   if(prog->ULen==-1) {
      printf("%4s: %-8s %s\033[K\n",
         prog->PackerName,  prog->Activity,  prog->FileName);
      fflush(stdout);
   } else if( prog->Type!=XPKPROG_END ) {
      printf("%4s: %-8s (%3ld%% done, %2ld%% CF, %6ld cps) %s\033[K\r",
         prog->PackerName,  prog->Activity,   prog->Done,
         prog->CF,          prog->Speed,      prog->FileName);
      fflush(stdout);
   } else {
      printf("%4s: %-8s (%3ldK, %2ld%% CF, %6ld cps) %s\033[K\n",
         prog->PackerName,  prog->Activity,   prog->ULen/1024,
         prog->CF,          prog->Speed,      prog->FileName);

   }
   return (long)SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
}

