home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / System / XADmaster / xad_dev / Sources / tools / xadUnFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-01  |  30.8 KB  |  1,025 lines

  1. #ifdef MULTIFILE
  2.   #define NAME         "xadUnFileM"
  3. #else
  4.   #define NAME         "xadUnFile"
  5. #endif
  6. #define DISTRIBUTION "(Freeware) "
  7. #define REVISION     "22"
  8. #define DATE         "25.02.2001"
  9.  
  10. /* Programmheader
  11.  
  12.     Name:        xadUnFile
  13.     Author:        SDI
  14.     Distribution:    Freeware
  15.     Description:    dearchives file archives
  16.     Compileropts:    -
  17.     Linkeropts:    -gsi -l amiga
  18.  
  19.  1.0   13.09.98 : first version
  20.  1.1   18.11.98 : added FILE parameter and directory creation
  21.  1.2   03.02.99 : added corrupt message
  22.  1.3   07.02.99 : added missing "group crunched" handling
  23.  1.4   16.03.99 : errors no longer abort decrunching
  24.  1.5   21.06.99 : added support for multiple input files and renaming
  25.  1.6   04.07.99 : bug fix
  26.  1.7   18.07.99 : added SHOWPROT, reduced status prints, added QUIT,
  27.     splitted in xadUnFile and xadUnFileM
  28.  1.8   19.08.99 : also strips "/" at name start for NOABS
  29.  1.9   15.09.99 : forgot to set date/comment/bits for directories
  30.  1.10  28.09.99 : added NAMESIZE keyword
  31.  1.11  01.11.99 : added SFS keyword
  32.  1.12  07.12.99 : added NOKILLPART keyword
  33.  1.13  17.12.99 : added VERBOSE mode
  34.  1.14  14.01.00 : added DARC, ENTRY, DIMG
  35.  1.15  12.02.00 : added auto DIMG and pattern support
  36.  1.16  05.03.00 : bug fixes
  37.  1.17  19.03.00 : support for XADFIF_NOUNCRUNCHSIZE
  38.  1.18  28.05.00 : added final report
  39.  1.19  04.06.00 : added multi-filesystem support
  40.  1.20  27.07.00 : fixed multi-filesystem support for empty fs parts
  41.  1.21  28.01.01 : returns RETURN_ERROR if errors occured
  42.  1.22  25.02.01 : GetInfo supports progress hook now
  43. */
  44.  
  45. #include <proto/xadmaster.h>
  46. #include <proto/exec.h>
  47. #include <proto/dos.h>
  48. #include <exec/memory.h>
  49. #include <dos/dosasl.h>
  50. #include <utility/hooks.h>
  51. #include "SDI_version.h"
  52. #include "SDI_compiler.h"
  53. #define SDI_TO_ANSI
  54. #include "SDI_ASM_STD_protos.h"
  55.  
  56. struct xadMasterBase *    xadMasterBase = 0;
  57. struct DosLibrary *     DOSBase = 0;
  58. struct ExecBase *     SysBase  = 0;
  59.  
  60. #define MINPRINTSIZE    51200    /* 50KB */
  61. #define NAMEBUFSIZE    512
  62. #define PATBUFSIZE    (NAMEBUFSIZE*2+10)
  63.  
  64. #ifdef MULTIFILE
  65. #define PARAM    "FROM/A/M,DEST=DESTDIR/K,PASSWORD/K,FILE/K,"    \
  66.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  67.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  68.         "OW=OVERWRITE/S,SP=SHOWPROT/S,VERBOSE/S,"    \
  69.         "DARC=DISKARCHIVE/S,ENTRY/K/N,DIMG=DISKIMAGE/S,"\
  70.         "NA=NOABS/S,NC=NOCOMMENT/S,ND=NODATE/S,"    \
  71.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  72.         "NT=NOTREE/S"
  73. #else
  74. #define PARAM    "FROM/A,DEST=DESTDIR,PASSWORD/K,FILE/M,"    \
  75.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  76.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  77.         "OW=OVERWRITE/S,SP=SHOWPROT/S,VERBOSE/S,"    \
  78.         "DARC=DISKARCHIVE/S,ENTRY/K/N,DIMG=DISKIMAGE/S,"\
  79.         "NA=NOABS/S,NC=NOCOMMENT/S,ND=NODATE/S,"    \
  80.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  81.         "NT=NOTREE/S"
  82. #endif
  83.  
  84. #ifdef MULTIFILE
  85. #define OPTIONS1 \
  86.   "FROM       The input archive file(s)\n"                \
  87.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  88.   "PASSWORD   A password for encrypted archives\n"            \
  89.   "FILE       Filename (with patterns) to be extracted\n"
  90. #else
  91. #define OPTIONS1 \
  92.   "FROM       The input archive file (no patterns allowed)\n"        \
  93.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  94.   "PASSWORD   A password for encrypted archives\n"            \
  95.   "FILE       Filename(s) (with patterns) to be extracted\n"
  96. #endif
  97.  
  98. #define OPTIONS2 \
  99.   "NAMESIZE   Names with more characters result in rename request\n"    \
  100.   "FFS=OFS    Sets NAMESIZE to 30\n"                    \
  101.   "SFS        Sets NAMESIZE to 100\n"                    \
  102.   "INFO       Shows archive information without extracting\n"        \
  103.   "QUIET      Turns of progress report and user interaction\n"        \
  104.   "ASKMAKEDIR You get asked before a directory is created\n"        \
  105.   "OVERWRITE  Files are overwritten without asking\n"            \
  106.   "SHOWPROT   Show protection information with LIST\n"            \
  107.   "VERBOSE    Print some more information with INFO\n"            \
  108.   "DARC       input file is an disk archive\n"                \
  109.   "ENTRY      entry number for DARC, if not the first one\n"        \
  110.   "DIMG          input file is an disk image (ADF file)\n"            \
  111.   "NOABS      Do not extract absolute path name parts\n"        \
  112.   "NOCOMMENT  No filenote comments are extracted or displayed\n"    \
  113.   "NODATE     Creation date information gets not extracted\n"        \
  114.   "NOEXTERN   Turns off usage of external clients\n"            \
  115.   "NOKILLPART Do not delete partial or corrupt output files.\n"        \
  116.   "NOPROT     Protection information gets not extracted\n"        \
  117.   "NOTREE     Files are extracted without subdirectories\n"
  118.  
  119. struct xHookArgs {
  120.   STRPTR name;
  121.   ULONG flags;
  122.   ULONG finish;
  123.   ULONG lastprint;
  124. };
  125.  
  126. struct Args {
  127. #ifdef MULTIFILE
  128.   STRPTR * from;
  129.   STRPTR   destdir;
  130.   STRPTR   password;
  131.   STRPTR   file;
  132. #else
  133.   STRPTR   from;
  134.   STRPTR   destdir;
  135.   STRPTR   password;
  136.   STRPTR * file;
  137. #endif
  138.   LONG *   namesize;
  139.   ULONG    ffs;
  140.   ULONG       sfs;
  141.   ULONG    info;
  142.   ULONG    quiet;
  143.   ULONG    askmakedir;
  144.   ULONG    overwrite;
  145.   ULONG       showprot;
  146.   ULONG    verbose;
  147.   ULONG    diskarchive;
  148.   LONG *   entry;
  149.   ULONG    diskimage;
  150.   ULONG    noabs;
  151.   ULONG    nocomment;
  152.   ULONG    nodate;
  153.   ULONG    noextern;
  154.   ULONG       nokillpart;
  155.   ULONG    noprot;
  156.   ULONG    notree;
  157. };
  158.  
  159. ASM(ULONG) progrhook(REG(a0, struct Hook *),
  160.   REG(a1, struct xadProgressInfo *));
  161.  
  162. void ShowProt(ULONG i);
  163. LONG CheckNameSize(STRPTR name, ULONG size);
  164. void CalcPercent(ULONG cr, ULONG ucr, ULONG *p1, ULONG *p2);
  165.  
  166. #ifndef MULTIFILE
  167.   LONG CheckName(STRPTR *pat, STRPTR name);
  168. #else
  169.   STRPTR *GetNames(STRPTR *names);
  170. #endif
  171.  
  172. ULONG start(void)
  173. {
  174.   ULONG ret = RETURN_FAIL, numerr = 0;
  175.   struct DosLibrary *dosbase;
  176.  
  177.   SysBase = (*((struct ExecBase **) 4));
  178.   { /* test for WB and reply startup-message */
  179.     struct Process *task;
  180.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  181.     {
  182.       WaitPort(&task->pr_MsgPort);
  183.       Forbid();
  184.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  185.       return RETURN_FAIL;
  186.     }
  187.   }
  188.  
  189.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  190.   {
  191.     LONG err = 0;
  192.     struct xadMasterBase *xadmasterbase;
  193.  
  194.     DOSBase = dosbase;
  195.     if((xadmasterbase = (struct xadMasterBase *)
  196.     OpenLibrary("xadmaster.library", 10)))
  197.     {
  198.       struct Args args;
  199.       struct RDArgs *rda;
  200.       
  201.       memset(&args, 0, sizeof(struct Args));
  202.       xadMasterBase = xadmasterbase;
  203.  
  204.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  205.       {
  206.         rda->RDA_ExtHelp = OPTIONS1 OPTIONS2;
  207.  
  208.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  209.         {
  210.           LONG namesize = 0;
  211.       struct Hook prhook;
  212.       UBYTE filename[NAMEBUFSIZE];
  213.       struct xHookArgs xh;
  214.  
  215. #ifdef MULTIFILE
  216.       STRPTR *argstring;
  217. #endif
  218.  
  219.       xh.name = filename;
  220.       xh.flags = xh.finish = xh.lastprint = 0;
  221.  
  222.       /* Note! The hook may change the filename!!! */
  223.           memset(&prhook, 0, sizeof(struct Hook));
  224.           prhook.h_Entry = (ULONG (*)()) progrhook;
  225.           prhook.h_Data = &xh;
  226.           
  227.           if(args.namesize && *args.namesize > 0)
  228.             namesize = *args.namesize;
  229.           else if(args.ffs)
  230.             namesize = 30;
  231.           else if(args.sfs)
  232.             namesize = 100;
  233.  
  234. #ifdef MULTIFILE
  235.       if(!(args.from = argstring = GetNames(args.from))) /* correct the argument list */
  236.             ;
  237.           else if(!(*argstring))
  238.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  239.       else /* comes together with following if! */
  240. #endif
  241.       if(args.destdir || args.info)
  242.       {
  243.             ULONG numfile = 0, numdir = 0;
  244.         struct xadArchiveInfo *ai;
  245.             struct TagItem ti[5];
  246.             struct TagItem ti2[5];
  247.             LONG loop = 2;
  248.             
  249.             ti[1].ti_Tag = XAD_NOEXTERN;
  250.         ti[1].ti_Data = args.noextern;
  251.         ti[2].ti_Tag = args.password ? XAD_PASSWORD : TAG_IGNORE;
  252.         ti[2].ti_Data = (ULONG) args.password;
  253.         ti[3].ti_Tag = args.entry ? XAD_ENTRYNUMBER : TAG_IGNORE;
  254.         ti[3].ti_Data = args.entry ? *args.entry : 1;
  255.         ti[4].ti_Tag = TAG_DONE;
  256.  
  257.         ti2[1].ti_Tag = XAD_NOEMPTYERROR;
  258.         ti2[1].ti_Data = TRUE;
  259.         ti2[2].ti_Tag = args.quiet ? TAG_IGNORE : XAD_PROGRESSHOOK;
  260.         ti2[2].ti_Data = (ULONG) &prhook;
  261.         ti2[3].ti_Tag = TAG_DONE;
  262.         ti2[4].ti_Tag = TAG_DONE; /* needed later for loop */
  263.  
  264.         if((ai = (struct xadArchiveInfo *)
  265.         xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  266.         {
  267. #ifdef MULTIFILE
  268.           if(*(args.from+1))
  269.           {
  270.             struct xadSplitFile *sf = 0, *sf2, *sf0 = 0;
  271.         while(*args.from && !err)
  272.         {
  273.           if((sf2 = xadAllocObjectA(XADOBJ_SPLITFILE, 0)))
  274.           {
  275.             if(sf)
  276.             {
  277.               sf->xsf_Next = sf2; sf = sf2;
  278.             }
  279.             else
  280.               sf0 = sf = sf2;
  281.             sf->xsf_Type = XAD_INFILENAME;
  282.             sf->xsf_Data = (ULONG) *(args.from++);
  283.           }
  284.           else
  285.             err = XADERR_NOMEMORY;
  286.         }
  287.             if(!err)
  288.             {
  289.               if(args.diskarchive)
  290.               {
  291.                 ti[0].ti_Tag = XAD_INSPLITTED;
  292.                 ti[0].ti_Data = (ULONG) sf0;
  293.  
  294.             ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  295.             ti2[0].ti_Data = (ULONG) ti;
  296.                 if((err = xadGetDiskInfoA(ai, ti2)))
  297.                 {
  298.                   ti2[0].ti_Tag = XAD_INSPLITTED;
  299.                   ti2[0].ti_Data = (ULONG) sf0;
  300.                   if(!xadGetDiskInfoA(ai, ti2))
  301.                     err = 0;
  302.                 }
  303.               }
  304.               else if(args.diskimage)
  305.               {
  306.                 ti2[0].ti_Tag = XAD_INSPLITTED;
  307.                 ti2[0].ti_Data = (ULONG) sf0;
  308.                 err = xadGetDiskInfoA(ai, ti2);
  309.               }
  310.               else
  311.               {
  312.                 err = xadGetInfo(ai, XAD_INSPLITTED, sf0, XAD_NOEXTERN,
  313.                 args.noextern, args.password ? XAD_PASSWORD : TAG_IGNORE,
  314.                 args.password, args.quiet ? TAG_IGNORE : XAD_PROGRESSHOOK,
  315.                 &prhook, TAG_DONE);
  316.                 --loop;
  317.               }
  318.             }
  319.             while(sf0)
  320.             {
  321.               sf2 = sf0; sf0 = sf0->xsf_Next;
  322.               xadFreeObjectA(sf2, 0);
  323.             }
  324.           }
  325.           else if(args.diskarchive)
  326.           {
  327.             ti[0].ti_Tag = XAD_INFILENAME;
  328.             ti[0].ti_Data = (ULONG) *args.from;
  329.  
  330.         ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  331.         ti2[0].ti_Data = (ULONG) ti;
  332.             if((err = xadGetDiskInfoA(ai, ti2)))
  333.             {
  334.               ti2[0].ti_Tag = XAD_INFILENAME;
  335.               ti2[0].ti_Data = (ULONG) *args.from;
  336.               if(!xadGetDiskInfoA(ai, ti2))
  337.                 err = 0;
  338.             }
  339.           }
  340.           else if(args.diskimage)
  341.           {
  342.             ti2[0].ti_Tag = XAD_INFILENAME;
  343.             ti2[0].ti_Data = (ULONG) *args.from;
  344.             err = xadGetDiskInfoA(ai, ti2);
  345.           }
  346.           else
  347.           {
  348.             err = xadGetInfo(ai, XAD_INFILENAME, *args.from,
  349.             XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
  350.             TAG_IGNORE, args.password, args.quiet ? TAG_IGNORE : XAD_PROGRESSHOOK,
  351.             &prhook, TAG_DONE);
  352.             --loop;
  353.           }
  354. #else
  355.           if(args.diskarchive)
  356.           { 
  357.             ti[0].ti_Tag = XAD_INFILENAME;
  358.             ti[0].ti_Data = (ULONG) args.from;
  359.  
  360.         ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  361.         ti2[0].ti_Data = (ULONG) ti;
  362.             if((err = xadGetDiskInfoA(ai, ti2)))
  363.             {
  364.               ti2[0].ti_Tag = XAD_INFILENAME;
  365.               ti2[0].ti_Data = (ULONG) args.from;
  366.               if(!xadGetDiskInfoA(ai, ti2))
  367.                 err = 0;
  368.             }
  369.           }
  370.           else if(args.diskimage)
  371.           {
  372.             ti2[0].ti_Tag = XAD_INFILENAME;
  373.             ti2[0].ti_Data = (ULONG) args.from;
  374.             err = xadGetDiskInfoA(ai, ti2);
  375.           }
  376.           else
  377.           {
  378.             err = xadGetInfo(ai, XAD_INFILENAME, args.from,
  379.             XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
  380.             TAG_IGNORE, args.password, args.quiet ? TAG_IGNORE :
  381.             XAD_PROGRESSHOOK, &prhook, TAG_DONE);
  382.             --loop;
  383.           }
  384. #endif
  385.  
  386.           while(!err && loop)
  387.           {
  388.             if(ai->xai_Flags & XADAIF_FILECORRUPT)
  389.               Printf("!!! The archive file has some corrupt data. !!!\n");
  390.             if(args.info)
  391.             {
  392.               struct xadFileInfo *xfi;
  393.               ULONG grsize = 0;
  394.               if(ai->xai_Client)
  395.                 Printf("ClientName: %s\n", ai->xai_Client->xc_ArchiverName);
  396.           Printf("Size     CrndSize Ratio Date       Time     %s%sName\n",
  397.           args.verbose ? "Info           " : "",args.showprot ? "Protection       " : "");
  398.  
  399.               xfi = ai->xai_FileInfo;
  400.               while(xfi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  401.               {
  402.                 if(!(xfi->xfi_Flags & XADFIF_GROUPED))
  403.                   grsize = 0;
  404.             if(xfi->xfi_Flags & XADFIF_DIRECTORY)
  405.             {
  406.                   Printf("   <dir>    <dir>       %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  407.                   xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  408.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  409.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  410.               if(args.verbose)
  411.                 Printf("%-15s", xfi->xfi_EntryInfo);
  412.                   if(args.showprot)
  413.                     ShowProt(xfi->xfi_Protection);
  414.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  415.                   xfi->xfi_FileName);
  416.                 }
  417.             else if(xfi->xfi_Flags & XADFIF_GROUPED)
  418.             {
  419.                   Printf("%8ld   merged  n/a  %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  420.                   xfi->xfi_Size, xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  421.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  422.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  423.               if(args.verbose)
  424.                 Printf("%-15s", xfi->xfi_EntryInfo);
  425.                   if(args.showprot)
  426.                     ShowProt(xfi->xfi_Protection);
  427.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  428.                   xfi->xfi_FileName);
  429.                   grsize += xfi->xfi_Size;
  430.                   if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
  431.                   {
  432.                 ULONG i, j;
  433.               
  434.             CalcPercent(xfi->xfi_GroupCrSize, grsize, &i, &j);
  435.                     Printf("%8ld %8ld %2ld.%1ld%%\n", grsize, xfi->xfi_GroupCrSize, i, j);
  436.                     grsize = 0;
  437.                   }
  438.             }
  439.             else if(xfi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  440.             {
  441.                   Printf("<nosize> %8ld       %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  442.                   xfi->xfi_CrunchSize, xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  443.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  444.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  445.               if(args.verbose)
  446.                 Printf("%-15s", xfi->xfi_EntryInfo);
  447.                   if(args.showprot)
  448.                     ShowProt(xfi->xfi_Protection);
  449.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  450.                   xfi->xfi_FileName);
  451.                 }
  452.             else
  453.             {
  454.               ULONG i, j;
  455.               
  456.               CalcPercent(xfi->xfi_CrunchSize, xfi->xfi_Size, &i, &j);
  457.                   Printf("%8ld %8ld %2ld.%1ld%% %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  458.                   xfi->xfi_Size, xfi->xfi_CrunchSize, i, j,
  459.                   xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  460.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  461.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  462.               if(args.verbose)
  463.                 Printf("%-15s", xfi->xfi_EntryInfo);
  464.                   if(args.showprot)
  465.                     ShowProt(xfi->xfi_Protection);
  466.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  467.                   xfi->xfi_FileName);
  468.                 }
  469.                 if(xfi->xfi_Flags & XADFIF_LINK)
  470.                   Printf("link: %s\n", xfi->xfi_LinkName);
  471.                 if(xfi->xfi_Comment && !args.nocomment)
  472.                   Printf(": %s\n", xfi->xfi_Comment);
  473. #ifdef DEBUG
  474.             if(xfi->xfi_Flags)
  475.             {
  476.                   Printf("Flags: ");
  477.                   if(xfi->xfi_Flags & XADFIF_CRYPTED)
  478.                     Printf("XADFIF_CRYPTED ");
  479.                   if(xfi->xfi_Flags & XADFIF_DIRECTORY)
  480.                     Printf("XADFIF_DIRECTORY ");
  481.                   if(xfi->xfi_Flags & XADFIF_LINK)
  482.                     Printf("XADFIF_LINK ");
  483.                   if(xfi->xfi_Flags & XADFIF_INFOTEXT)
  484.                     Printf("XADFIF_INFOTEXT ");
  485.                   if(xfi->xfi_Flags & XADFIF_GROUPED)
  486.                     Printf("XADFIF_GROUPED ");
  487.                   if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
  488.                     Printf("XADFIF_ENDOFGROUP ");
  489.                   if(xfi->xfi_Flags & XADFIF_NODATE)
  490.                     Printf("XADFIF_NODATE ");
  491.                   Printf("\n");
  492.                 }
  493. #endif
  494.                 if(xfi->xfi_Flags & XADFIF_CRYPTED)
  495.                   Printf("The entry is encrypted.\n");
  496.                 if(xfi->xfi_Flags & XADFIF_PARTIALFILE)
  497.                   Printf("The entry is no complete file.\n");
  498.                 xfi = xfi->xfi_Next;
  499.               }
  500.               ret = 0;
  501.             }
  502.             else
  503.             {
  504.           struct xadFileInfo *fi;
  505. #ifdef MULTIFILE
  506.             UBYTE parsebuf[PATBUFSIZE];
  507. #endif
  508.           ret = 0;
  509.           fi = ai->xai_FileInfo;
  510.  
  511. #ifdef MULTIFILE
  512.             if(!args.file || ParsePatternNoCase(args.file, parsebuf, PATBUFSIZE) >= 0)
  513. #endif
  514.             {
  515.             while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && !xh.finish)
  516.             {
  517. #ifdef MULTIFILE
  518.               if(!args.file || MatchPatternNoCase(parsebuf, args.notree ?
  519.               FilePart(fi->xfi_FileName) : fi->xfi_FileName))
  520. #else
  521.               if(!args.file || CheckName(args.file, args.notree ?
  522.               FilePart(fi->xfi_FileName) : fi->xfi_FileName))
  523. #endif
  524.               {
  525.                 CopyMem(args.destdir, filename, strlen(args.destdir)+1);
  526.             if(stricmp(args.destdir, "NIL:"))
  527.             {
  528.                   if(args.notree)
  529.                     AddPart(filename, FilePart(fi->xfi_FileName), NAMEBUFSIZE);
  530.                   else if(!args.noabs)
  531.                     AddPart(filename, fi->xfi_FileName, NAMEBUFSIZE);
  532.                   else
  533.                   {
  534.                     STRPTR fname = filename, f;
  535.  
  536.                 if(*args.destdir)
  537.                 {
  538.                       fname += strlen(args.destdir)-1;
  539.                       if(*fname != ':' && *fname != '/')
  540.                         *(++fname) = '/';
  541.                       ++fname;
  542.                     }
  543.                 for(f = fi->xfi_FileName; *f == '/' || *f == ':'; ++f)
  544.                   ;
  545.                     for(; *f; ++f)
  546.                       *(fname++) = *f == ':' ? '/' : *f;
  547.                     *fname = 0;
  548.                   }
  549.                 }
  550.                 if(fi->xfi_Flags & XADFIF_LINK)
  551.                 {
  552.                   if(!args.quiet)
  553.                     Printf("Skipped Link\n");
  554.                 }
  555.                 else if(fi->xfi_Flags & XADFIF_DIRECTORY)
  556.                 {
  557.                   if(!args.notree)
  558.                   {
  559.                     BPTR a;
  560.                     LONG err = 0, i = 0;
  561.                     UBYTE r;
  562.                 ++numdir;
  563.                     while(filename[i] && !err)
  564.                     {
  565.                         for(;filename[i] && filename[i] != '/'; ++i)
  566.                         ;
  567.                         r = filename[i];
  568.                         filename[i] = 0;
  569.                   if((a = Lock(filename, SHARED_LOCK)))
  570.                           UnLock(a);
  571.                       else if((a = CreateDir(filename)))
  572.                             UnLock(a);
  573.                         else
  574.                             err = 1;
  575.                           filename[i++] = r;
  576.                     }
  577.                     if(!args.quiet)
  578.                     {
  579.                       if(err)
  580.                       {
  581.                         Printf("failed to create directory '%s'\n", fi->xfi_FileName);
  582.                         ++numerr;
  583.                       }
  584.                       else
  585.                         Printf("Created directory   : %s\n", filename);
  586.                     }
  587.                         if(!err)
  588.                         {
  589.                       struct DateStamp d;
  590.  
  591.                           if(!args.nodate && !(fi->xfi_Flags & XADFIF_NODATE)
  592.                           && !xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date,
  593.                           XAD_GETDATEDATESTAMP, &d, TAG_DONE))
  594.                             SetFileDate(filename, &d);
  595.                           if(!args.noprot)
  596.                             SetProtection(filename, fi->xfi_Protection);
  597.                           if(fi->xfi_Comment && !args.nocomment)
  598.                             SetComment(filename, fi->xfi_Comment);
  599.                           /* SetOwner ??? */
  600.                         }
  601.                   }
  602.                 } 
  603.                 else
  604.                 {
  605.                   struct DateStamp d;
  606.  
  607.               if(namesize)
  608.                 xh.finish = CheckNameSize(FilePart(filename), namesize);
  609.  
  610.               if(!xh.finish)
  611.               {
  612.                 LONG e;
  613.  
  614.                 ++numfile;
  615.  
  616.                 if(args.diskimage || args.diskarchive)
  617.                       e = xadDiskFileUnArc(ai, XAD_OUTFILENAME, filename,
  618.                           XAD_ENTRYNUMBER, fi->xfi_EntryNumber, XAD_MAKEDIRECTORY,
  619.                           !args.askmakedir, XAD_OVERWRITE, args.overwrite,
  620.                           XAD_NOKILLPARTIAL, args.nokillpart,  args.quiet ? TAG_IGNORE :
  621.                           XAD_PROGRESSHOOK, &prhook, TAG_DONE);
  622.                     else
  623.                       e = xadFileUnArc(ai, XAD_OUTFILENAME, filename,
  624.                           XAD_ENTRYNUMBER, fi->xfi_EntryNumber, XAD_MAKEDIRECTORY,
  625.                           !args.askmakedir, XAD_OVERWRITE, args.overwrite,
  626.                           XAD_NOKILLPARTIAL, args.nokillpart,  args.quiet ? TAG_IGNORE :
  627.                           XAD_PROGRESSHOOK, &prhook, TAG_DONE);
  628.  
  629.                         if(!e)
  630.                         {
  631.                           if(!args.nodate && !(fi->xfi_Flags & XADFIF_NODATE)
  632.                           && !xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date,
  633.                           XAD_GETDATEDATESTAMP, &d, TAG_DONE))
  634.                             SetFileDate(filename, &d);
  635.                           if(!args.noprot)
  636.                             SetProtection(filename, fi->xfi_Protection);
  637.                           if(fi->xfi_Comment && !args.nocomment)
  638.                             SetComment(filename, fi->xfi_Comment);
  639.                           /* SetOwner ??? */
  640.                         }
  641.                         else
  642.                           ++numerr;
  643.                       }
  644.                     }
  645.                   }
  646.                   fi = fi->xfi_Next;
  647.                 }
  648.               }
  649.             }
  650.             ti2[3].ti_Tag = XAD_STARTCLIENT;
  651.             ti2[3].ti_Data = (ULONG) ai->xai_Client->xc_Next;
  652.             xadFreeInfo(ai);
  653.             if(--loop)
  654.             {
  655.               loop = 0;
  656.               if(ti2[3].ti_Data)
  657.               {
  658.             xadFreeObjectA(ai, 0); /* realloc ai structure */
  659.                 if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  660.                 {
  661.                   if(!xadGetDiskInfoA(ai, ti2))
  662.                     loop = 2;
  663.                 }
  664.               }
  665.             }
  666.         if(!args.info && !loop && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  667.         {
  668.           Printf("Processed");
  669.           if(numfile)
  670.             Printf(" %ld file%s%s", numfile, numfile == 1 ? "" : "s", numdir ? " and" : "");
  671.           if(numdir)
  672.             Printf(" %ld director%s", numdir, numdir == 1 ? "y" : "ies");
  673.           if(!numfile && !numdir)
  674.             Printf(" nothing");
  675.           if(numerr)
  676.             Printf(", %ld error%s", numerr, numerr == 1 ? "" : "s");
  677.           Printf(".\n");
  678.         }
  679.           } /* xadGetInfo, loop */
  680.  
  681.           if(ai)
  682.             xadFreeObjectA(ai, 0);
  683.             } /* xadAllocObject */
  684.           }
  685.           else
  686.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  687.  
  688. #ifdef MULTIFILE
  689.       if(argstring)
  690.         FreeVec(argstring);
  691. #endif
  692.  
  693.           FreeArgs(rda);
  694.         } /* ReadArgs */
  695.         FreeDosObject(DOS_RDARGS, rda);
  696.       } /* AllocDosObject */
  697.  
  698.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  699.         SetIoErr(ERROR_BREAK);
  700.  
  701.       if(!args.quiet)
  702.       {
  703.         if(err)
  704.       Printf("An error occured: %s\n", xadGetErrorText(err));
  705.         else if(ret)
  706.           PrintFault(IoErr(), 0);
  707.       }
  708.  
  709.       CloseLibrary((struct Library *) xadmasterbase);
  710.     } /* OpenLibrary xadmaster */
  711.     else
  712.       Printf("Could not open xadmaster.library\n");
  713.     CloseLibrary((struct Library *) dosbase);
  714.   } /* OpenLibrary dos */
  715.  
  716.   if(!ret && numerr)
  717.     ret = RETURN_ERROR;
  718.  
  719.   return ret;
  720. }
  721.  
  722. /* Because of SAS-err, this cannot be SAVEDS */
  723. ASM(ULONG) progrhook(REG(a0, struct Hook *hook),
  724. REG(a1, struct xadProgressInfo *pi))
  725. {
  726.   ULONG ret = 0;
  727.   STRPTR name = ((struct xHookArgs *) (hook->h_Data))->name;
  728.  
  729.   switch(pi->xpi_Mode)
  730.   {
  731.   case XADPMODE_ASK:
  732.     ret |= ((struct xHookArgs *) (hook->h_Data))->flags;
  733.     if((pi->xpi_Status & XADPIF_OVERWRITE) && !(ret & XADPIF_OVERWRITE))
  734.     {
  735.       LONG r;
  736.  
  737.       Printf("File '%s' already exists, overwrite? (Y|A|S|\033[1mN\033[0m|Q|R): ",
  738.       pi->xpi_FileName);
  739.       Flush(Output());
  740.       SetMode(Input(), TRUE);
  741.       r = FGetC(Input());
  742.       SetMode(Input(), FALSE);
  743.       switch(r)
  744.       {
  745.       case 'a': case 'A':
  746.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_OVERWRITE;
  747.       case 'y': case 'Y': ret |= XADPIF_OVERWRITE; break;
  748.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  749.       case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1; break;
  750.       case 'r': case 'R':
  751.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  752.         Flush(Output());
  753.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  754.         r = strlen(name);
  755.         if(name[r-1] == '\n') /* skip return character */
  756.           name[--r] = 0;
  757.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  758.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  759.         {
  760.           while(r--)
  761.             pi->xpi_NewName[r] = name[r];
  762.           ret |= XADPIF_RENAME;
  763.         }
  764.         else
  765.           Printf("No memory to store new name\n");
  766.       }
  767.     }
  768.     if((pi->xpi_Status & XADPIF_ISDIRECTORY))
  769.     {
  770.       LONG r;
  771.  
  772.       Printf("File '%s' exists as directory, rename? (R|S|\033[1mN\033[0m|Q): ",
  773.       pi->xpi_FileName);
  774.       Flush(Output());
  775.       SetMode(Input(), TRUE);
  776.       r = FGetC(Input());
  777.       SetMode(Input(), FALSE);
  778.       switch(r)
  779.       {
  780.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  781.       case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1; break;
  782.       case 'r': case 'R':
  783.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  784.         Flush(Output());
  785.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  786.         r = strlen(name);
  787.         if(name[r-1] == '\n') /* skip return character */
  788.           name[--r] = 0;
  789.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  790.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  791.         {
  792.           while(r--)
  793.             pi->xpi_NewName[r] = name[r];
  794.           ret |= XADPIF_RENAME;
  795.         }
  796.         else
  797.           Printf("No memory to store new name\n");
  798.       }
  799.     }
  800.     if((pi->xpi_Status & XADPIF_MAKEDIRECTORY) &&
  801.     !(ret & XADPIF_MAKEDIRECTORY))
  802.     {
  803.       Printf("Directory of file '%s' does not exist, create? (Y|A|S|\033[1mN\033[0m|Q): ",
  804.       name);
  805.       Flush(Output());
  806.       SetMode(Input(), TRUE);
  807.       switch(FGetC(Input()))
  808.       {
  809.       case 'a': case 'A':
  810.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_MAKEDIRECTORY;
  811.       case 'y': case 'Y': ret |= XADPIF_MAKEDIRECTORY; break;
  812.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  813.       case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1;
  814.       }
  815.       SetMode(Input(), FALSE);
  816.     }
  817.     break;
  818.   case XADPMODE_PROGRESS:
  819.     if(pi->xpi_CurrentSize - ((struct xHookArgs *) (hook->h_Data))->lastprint >= MINPRINTSIZE)
  820.     {
  821.       if(pi->xpi_FileInfo->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  822.         Printf("\r\033[KWrote %8ld bytes: %s", pi->xpi_CurrentSize, name);
  823.       else
  824.         Printf("\r\033[KWrote %8ld of %8ld bytes: %s",
  825.         pi->xpi_CurrentSize, pi->xpi_FileInfo->xfi_Size, name);
  826.       Flush(Output());
  827.       ((struct xHookArgs *) (hook->h_Data))->lastprint = pi->xpi_CurrentSize;
  828.     }
  829.     break;
  830.   case XADPMODE_END: Printf("\r\033[KWrote %8ld bytes: %s\n",
  831.     pi->xpi_CurrentSize, name);
  832.     break;
  833.   case XADPMODE_ERROR: Printf("\r\033[K%s: %s\n", name,
  834.     xadGetErrorText(pi->xpi_Error));
  835.     break;
  836.   }
  837.  
  838.   if(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)) /* clear ok flag */
  839.     ret |= XADPIF_OK;
  840.  
  841.   return ret;
  842. }
  843.  
  844. void ShowProt(ULONG i)
  845. {
  846.   LONG j;
  847.   UBYTE buf[16], *b = "rwedrwedhsparwed";
  848.   
  849.   for(j = 0; j <= 11; ++j)
  850.     buf[j] = (i & (1<<(15-j))) ? b[j] : '-';
  851.   for(; j <= 15; ++j)
  852.     buf[j] = (i & (1<<(15-j))) ? '-' : b[j];
  853.  
  854.   Printf("%.16s ", buf);
  855. }
  856.  
  857. LONG CheckNameSize(STRPTR name, ULONG size)
  858. {
  859.   LONG ret = 0;
  860.   LONG r;
  861.  
  862.   if((r = strlen(name)) > size)
  863.   {
  864.     UBYTE buf[NAMEBUFSIZE];
  865.  
  866.     Printf("\r\033[KFilename '%s' exceeds name limit of %ld by %ld, rename? (Y|\033[1mN\033[0m|Q): ", name, size, r-size);
  867.  
  868.     Flush(Output());
  869.     SetMode(Input(), TRUE);
  870.     r = FGetC(Input());
  871.     SetMode(Input(), FALSE);
  872.     switch(r)
  873.     {
  874.     case 'q': case 'Q': ret = 1; break;
  875.     case 'y': case 'Y':
  876.       Printf("\r\033[KEnter new name for '%s':", name);
  877.       Flush(Output());
  878.       FGets(Input(), buf, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  879.       r = strlen(buf);
  880.       if(buf[r-1] == '\n') /* skip return character */
  881.         buf[--r] = 0;
  882.       Printf("\033[1F\033[K"); /* go up one line and clear it */
  883.       if(!(ret = CheckNameSize(buf, size)))
  884.       {
  885.         for(r = 0; buf[r]; ++r)
  886.           *(name++) = buf[r];
  887.         *name = 0;
  888.       }
  889.       break;
  890.     }
  891.   }
  892.   return ret;
  893. }
  894.  
  895. void CalcPercent(ULONG cr, ULONG ucr, ULONG *p1, ULONG *p2)
  896. {
  897.   ULONG i = 0, j = 0;
  898.  
  899.   if(cr < ucr)
  900.   {
  901.     if(cr > (0xFFFFFFFF/1000))
  902.       i = 1000 - cr / (ucr / 1000);
  903.     else
  904.       i = 1000 - (1000 * cr) / ucr;
  905.     j = i % 10;
  906.     i /= 10;
  907.   }
  908.   *p1 = i;
  909.   *p2 = j;
  910. }
  911.  
  912. #ifndef MULTIFILE
  913. /* would be better to store the pattern parse stuff and do it only once,
  914. but so it is a lot easier */
  915. LONG CheckName(STRPTR *pat, STRPTR name)
  916. {
  917.   UBYTE buf[PATBUFSIZE];
  918.   while(*pat)
  919.   {
  920.     if(ParsePatternNoCase(*(pat++), buf, PATBUFSIZE) >= 0)
  921.     {
  922.       if(MatchPatternNoCase(buf, name))
  923.         return 1;
  924.     } /* A scan failure means no recognition, should be an error print here */
  925.   }
  926.   return 0;
  927. }
  928. #else
  929. STRPTR *GetNames(STRPTR *names)
  930. {
  931.   struct AnchorPath *APath;
  932.   STRPTR *result = 0, s, f, *r;
  933.   ULONG *filelist, *fl = 0, *a, *b, retval = 0, namesize = 0;
  934.   LONG i;
  935.  
  936.   if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath)+512, MEMF_PUBLIC|MEMF_CLEAR)))
  937.   {
  938.     APath->ap_BreakBits = SIGBREAKF_CTRL_C;
  939.     APath->ap_Strlen = 512;
  940.  
  941.     while(*names && !retval)
  942.     {
  943.       filelist = 0;
  944.       for(retval = MatchFirst(*names, APath); !retval; retval = MatchNext(APath))
  945.       {
  946.         if(APath->ap_Info.fib_DirEntryType < 0)
  947.         {
  948.           i = strlen(APath->ap_Buf)+1;
  949.           if(!(a = (ULONG *) AllocVec(i+4, MEMF_ANY)))
  950.             break;
  951.           CopyMem(APath->ap_Buf, a+1, i);
  952.           namesize += i;
  953.           if(!filelist)
  954.           {
  955.             filelist = a; *a = 0;
  956.           }
  957.           else if(stricmp((STRPTR) (filelist+1), APath->ap_Buf) >= 0)
  958.           {
  959.             *a = (ULONG) filelist; filelist = a;
  960.           }
  961.           else
  962.           {
  963.             for(b = filelist; *b && (i = SDI_stricmp((STRPTR) (*b+4),
  964.             APath->ap_Buf)) < 0; b = (ULONG *) *b)
  965.               ;
  966.             *a = *b; *b = (ULONG) a;
  967.           }
  968.         }
  969.       }
  970.       if(fl)
  971.       {
  972.         for(b = fl; *b; b = (ULONG *) *b)
  973.           ;
  974.         *b = (ULONG) filelist;
  975.       }
  976.       else
  977.         fl = filelist;
  978.       MatchEnd(APath);
  979.       if(retval == ERROR_NO_MORE_ENTRIES)
  980.         retval = 0;
  981.       ++names;
  982.     }
  983.  
  984.     if(!retval)
  985.     {
  986.       i = 0;
  987.       for(b = fl; b; b = (ULONG *) *b)
  988.         ++i;
  989.       if((result = (STRPTR *)AllocVec((i+1)*sizeof(STRPTR)+namesize, MEMF_ANY)))
  990.       {
  991.         s = ((STRPTR) result)+((i+1)*sizeof(STRPTR));
  992.         i = 0;
  993.         for(b = fl; b; b = (ULONG *) *b)
  994.         {
  995.           result[i++] = s;
  996.           for(f = (STRPTR) (b+1); *f; ++f)
  997.             *(s++) = *f;
  998.           *(s++) = 0;
  999.         }
  1000.         result[i] = 0;
  1001.       }
  1002.     }
  1003.  
  1004.     while(fl)
  1005.     {
  1006.       a = (ULONG *) *fl;
  1007.       FreeVec(fl);
  1008.       fl = a;
  1009.     }
  1010.  
  1011.     FreeMem(APath, sizeof(struct AnchorPath)+512);
  1012.   }
  1013.  
  1014.   if(!retval)
  1015.   {
  1016.     Printf("Loading files in following order: ");
  1017.  
  1018.     for(r = result; *r; ++r)
  1019.       Printf("%s%s", *r, r[1] ? ", " : "\n");
  1020.   }
  1021.  
  1022.   return result;
  1023. }
  1024. #endif
  1025.