home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / varie / xad / developer / sources / tools / xadunfile.c < prev   
Encoding:
C/C++ Source or Header  |  2000-06-25  |  29.2 KB  |  980 lines

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