/*** HELP START ***//*
 
## >>> `%unzipLibrary()` macro: <<< <a name="unziplibrary-macro"></a> #######################  

The unzipLibrary() macro allows to unzip content of a SAS library. 
It is a *counterpart* to the `%zipLibrary()` macro and is *not* intended to work 
with zip files generated by other software (though it may in some cases).

Files can be unzipped from a single file
or from multiple files (named e.g. "dataset.sas7bdat.zip"). 
If a file is indexed also the index file is unzipped.

Source files can be deleted after decompression.

Status of decompression and processing time is reported. 

See examples below for the details.

### SYNTAX: ###################################################################

The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%unzipLibrary(
    path
  <,zip=>
  <,mode=>
  <,clean=> 
  <,libOut=>
)
~~~~~~~~~~~~~~~~~~~~~~~

**Arguments description**:

1. `path`          - *Required*, a path pointing to zipped file(s) location.
                     The path should be unquoted, e.g. `%unzipLibrary(/some/dir, ...)`.

* `zip =`          - *Optional*, When `mode=S` a name of the 
                     zip file containing SAS files to be unzipped.
                     
* `mode  = S`      - *Optional*, default value is `S`, 
                     indicates mode of decompression 
                     read from a single zip file (`SINGLE/S`) 
                     or from multiple files (`MULTI/M`)

* `clean = 0`      - *Optional*, default value is `0`,
                     should zip files be deleted after unzipping? 
                     `1` means *yes*, `0` means *no*. 

* `libOut =`       - *Optional*, default value is empty,
                     output library for a single zip file
                     decompression.

*//*** HELP END ***/

%macro unzipLibrary(
  path            /* path pointing the zip file(s) location */
 ,zip=            /* name of the zipped library to be unzipped */
 ,mode=S          /* mode of compression, default is "S", 
                     unzips a single zip file or multiple files */
 ,clean=0         /* should zip be deleted after unzipping? 1 = yes, 0 = no */
 ,libOut=         /* output library for unzipped files */
)
/secure des='Macro unzipLibrary allows to unzip content of a zip file containing sas files'
;
%local processing_time;
%let   processing_time = %sysfunc(datetime());
%local tmp_options;
%let   tmp_options = %sysfunc(getoption(notes));
options noNotes;

%if %superq(path)= %then
  %do;
    %put ERROR: The PATH parameter is null!;
    %goto errorUnzipLibrary;
  %end;

%if %qsysfunc(fileexist(&path.)) = 0 %then
  %do;
    %put ERROR: The path: %superq(PATH) does not exists!;
    %goto errorUnzipLibrary;
  %end;

data _null_;
  mode = upcase(symget("mode"));
  if mode not in ("S", "M", "SINGLE", "MULTI") then 
    do;
      mode = "S";
      put "WARNING: Improper Mode value.";
      put "WARNING- Use: SINGLE/S or MULTI/M";
      put "WARNING- Mode set to SINGLE.";
    end;
  call symputX('mode', char(upcase(mode),1), "L");

  clean = input(symget("clean"), ?? best32.);
  if clean not in (0 1) then 
  do;
    clean = 0;
    put "WARNING: Improper Clean value.";
    put "WARNING- Use: 0 or 1";
    put "WARNING: Clean set to 0.";
  end;
  call symputX('clean', clean, "L");
run;

%if &mode. = S and %superq(zip)= %then
  %do;
    %put ERROR: The ZIP= parameter is null in SINGLE mode!;
    %goto errorUnzipLibrary;
  %end;


%local _testLB_ ;
%let   _testLB_ = i%sysfunc(datetime(),hex7.);

%if %superq(libOut)= %then
  %do;
    %let libOut = &path.;
  %end;
%else
  %do;
    libname &_testLB_. (&libOut. &libOut.);
    %let libOut = %scan(%sysfunc(pathname(&_testLB_.)),1,( ),q);
    libname &_testLB_. clear;
  %end;

options notes;
%put NOTE: LibOut is: &libOut.;
%put;
options noNotes;


%local inZIP in out;
%let inZIP = z%sysfunc(datetime(),hex7.);
%let   inF = i%sysfunc(datetime(),hex7.);
%let  outF = o%sysfunc(datetime(),hex7.);

data _null_;

  length mode $ 1;
  mode = upcase(symget("mode"));

  /* set input ZIP/Directory depending on mode S/M */ 
  rc0 = filename("&inZIP.");
  if mode = "S" then
    rc0 = filename("&inZIP.", "&path./&zip..zip", "ZIP", "lrecl=1 recfm=n");
  if mode = "M" then
    rc0 = filename("&inZIP.", "&path.");
  rc0msg = sysmsg();
  if rc0 then put "assign zip: " @15 (rc0:) (=);

  if not fexist("&inZIP.") then
    do;
      if mode = "S" then
        put "ERROR: File &path./&zip..zip does nor exist!";
      if mode = "M" then
        put "ERROR: File &path. does nor exist!";
      put "ERROR- Aborting.";
      stop;
    end;

  did = dopen("&inZIP.");
  if not did then
    do;
      if mode = "S" then
        put "ERROR: Cannot open &path./&zip..zip file!";
      if mode = "M" then
        put "ERROR: Cannot open &path. directory!";
      put "ERROR- Aborting.";
      stop;
    end;

  do i=1 to dnum(did);
      file = dread(did, i);
      /* in Multiple mode ignore non zip files */
      if mode = "M" and scan(file, -1, ".") NE "zip" then continue;
      put "STATUS FOR " file;

      /* set input depending on mode */ 
      if mode = "S" then
        rc1 = filename("&inF.", "&path./&zip..zip", "ZIP", "member='" !! strip(file) !! "' lrecl=1 recfm=n");
      if mode = "M" then
        rc1 = filename("&inF.", "&path./" !! strip(file), "ZIP", "lrecl=1 recfm=n");
      rc1msg = sysmsg();
      if rc1 then put "assign input: " @15 (rc1:) (=);

      fileSAS = catx(".", scan(file,1), scan(file,2)); /* a.sas7bdat.zip -> a.sas7bdat */
      rc2 = filename("&outF.", catx("/", dequote(symget("libOut")), fileSAS), "DISK", "lrecl=1 recfm=n");
      rc2msg = sysmsg();
      if rc2 then put "assign output: " @15 (rc2:) (=);

      rc3 = fcopy("&inF.", "&outF.");
      rc3msg = sysmsg();
      if rc3 then put "copying: " @15 (rc3:) (=);

      rc4 = ^fexist("&outF.");
      rc4msg = "Error. Unzipped file does not exist!";
      if rc4 then put "check unzip: " @15 (rc4:) (=);
      ifAllUnzipped + rc4;

      if not sum(rc1, rc2, rc3, rc4) then put " O.K.";

      if &clean. and mode = "M" and rc4 = 0 then
        do;
          rc1 = filename("&inF.", "&path./" !! strip(file));
          rcX = fdelete("&inF.");
          rcXmsg = sysmsg();
          if rcX then put "deleting: " @15 (rcX:) (=);
          put " Removing &path./" file "file." /; 
        end;

      rcY = filename("&inF.");
      rcZ = filename("&outF.");
  end;

  did = dclose(did);


  if &clean. and mode = "S" and ifAllUnzipped = 0 then
    do;
      put / "Removing &path./&zip..zip file.";
      rcX = fdelete("&inZIP."); 
    end;

  rc0 = filename("&inZIP.");
  rc0msg = sysmsg();
  rc0 = filename("&inZIP.");
  rc0msg = sysmsg();
run;

%errorUnzipLibrary:
options notes;
%put;
%put Processing time was: %sysevalf(%sysfunc(datetime()) - &processing_time.) s.;
%put;
options &tmp_options.;
%mend unzipLibrary;



/*** HELP START ***//*

### EXAMPLES AND USECASES: ####################################################

**EXAMPLE 1.** Generate data:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas

options dlcreatedir;
  libname test1 "%sysfunc(pathname(work))/test1";
  libname test2 "%sysfunc(pathname(work))/test2";
  libname test3 (test1 test2);
  libname test4 "%sysfunc(pathname(work))/test4";
options nodlcreatedir;

%put %sysfunc(pathname(test3));
%put %sysfunc(pathname(test4));

data 
  test1.A(index=(model)) 
  test1.B 
  test2.C 
  test2.D(index=(model make io=(invoice origin))) 
;
  set sashelp.cars;
run;

data test1.B2 / view=test1.B2;
  set test1.B;
  output;
  output;
run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


**EXAMPLE 2.** Use data from Example 1.
               First zip content of the `test3` library
               to `test4` location into one zip file
               and delete source files.
               Next unzip `test3.zip` library into the 
               `test4` location and delete the zip file.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%zipLibrary(test3, clean=1, libOut=test4)


%unzipLibrary(%sysfunc(pathname(test4)), zip=test3, clean=1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


**EXAMPLE 3.** Use data from Example 1.
               First zip content of the `test1` library
               into multiple zip files and delete source files.
               Next unzip `*.zip` files in `test1` 
               location and delete zipped files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%zipLibrary(test1, mode=M, clean=1)


%unzipLibrary(%sysfunc(pathname(test1)), mode=M, clean=1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


**EXAMPLE 4.** First zip content of the `sashelp` library
               into `work` library.
               Next unzip `sashelp.zip` file in `work` 
               location and delete zip file.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%zipLibrary(sashelp, mode=S, clean=0, libOut=work)


%unzipLibrary(%sysfunc(pathname(work)), zip=sashelp, mode=S, clean=1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*//*** HELP END ***/
