/*----------------------------------------------------------------------*/
/* Sentinel package of SAS macros to assist with environment setup      */
/*                                                                      */
/*   List of macros included in package                                 */
/*     - SOC_CLEAN_PATHS  ... cleans & validates path-name(s)           */
/*     - SOC_DIREXIST ... checks if directory exists                    */
/*     - SOC_LIB ... conditionally assigns libname                      */
/*                                                                      */
/*----------------------------------------------------------------------*/
* CONTACT INFO: 
* Sentinel Coordinating Center
* info@sentinelsystem.org
*
*------------------------------------------------------------------------------;


 /*****************************************************************************
*                               SENTINEL MACRO
******************************************************************************
* NAME:  soc_clean_paths
*
* PURPOSE: Clean up path(s) according to soc conventions, then validates
*
* MAJOR STEPS:
*  1. Checks if the &paths parameter is missing, if so, the macro will print
*     an error message and exit
*  2. Removes any double spaces within the paths list and replaces
*     them with single spaces
*  3. Loops through each path provided and:
*    - Replaces back slashes (\) with forward slashes (/)
*    - Checks if path ends with forward slash, appending one if necessary
*    - Checks the existence of the directory using the %soc_dirExist macro.
*      If the directory does not exist, the macro will print an error message
*      indicating that the path does not exist and exits
*  4. Returns the cleaned path list to the calling environment.
*
* KEY DEPENDENCIES/CONSTRAINTS:  calls macro soc_dirExist
*
*------------------------------------------------------------------------------
* PARAMETERS
*  paths ... name of path, without surrounding quotes, separated by a single
*  space (e.g. X:\project-xyz or /path1/ /path2/)
*
*  print_paths ... an optional parameter that determines whether the error message
*  should include the path that does not exist. If set to 0, the error message
*  will not include the path. If set to 1, the error message will include the path.
*------------------------------------------------------------------------------
* HISTORY:
*  Create date (mm/dd/yy):  08/27/13
*  Last modified date (mm/dd/yy): 01/10/19
**********************************************************************************/

/* System options */
options nosymbolgen nomlogic;
options ls=100 nocenter ;
options obs=MAX ;
options msglevel=i ;
options mprint mprintnest ;
options errorcheck=strict errors=0 ;
options merror serror ;
options dkricond=error dkrocond=error mergenoby=warn;
options dsoptions=nonote2err noquotelenmax ;
options reuse=no ;
options fullstimer ;
options missing = . ;
options validvarname = v7;
options fmterr ;
options minoperator mindelimiter='' ;  /*enable "IN" in macro statement */
options nodsnferr ;
options append=(fmtsearch=(dplocal dplocalo));
options dlcreatedir;   /* [no]dlcreatedir --> [dis]allows folder creation */

%macro soc_clean_paths(paths,print_path)/parmbuff;
  %local j ln subpath temppath;

  %if %length(%superq(paths)) eq 0 %then %do;
    %put The parameter path must be non-missing. ;
    %abort cancel ;
  %end ;

  /* remove any double spaces in the paths list and replace with single space */
  %let paths=%qsysfunc(translate(&paths,%str(/),%str(\)));

  %do j=1 %to %qsysfunc(countw(&paths.,%str( )));
    %let subpath=%qscan(&paths,&j,%str( ));
    %let ln=%length(&subpath);

    %if %qsubstr(&subpath,&ln,1) ne %str(/) %then %do;
      %let subpath=&subpath./;
    %end;

    %let d_exist = %soc_dirExist(&subpath) ;
    %if &d_exist eq 0 %then %do ;
      %if &print_path. = 0 %then %do;
        %put Path does not exist;
      %end;
      %else %do;
        %put Path &subpath. does not exist;
      %end;
      %abort cancel;
    %end ;
  %let temppath=&temppath. &subpath.;
  %end;
  %let paths=%qleft(&temppath);
  &paths   /* returns value to calling environment, like a function */
%mend soc_clean_paths;

%macro soc_dirExist(dir) ; 
  /*****************************************************************************
  *                               SENTINEL MACRO
  ******************************************************************************
  * NAME:  soc_dirExist
  *
  * PURPOSE:  Checks if a directory exists, returning 1 if exists, 0 if not, 
  *           aborting if directory is missing.
  *------------------------------------------------------------------------------
  * USER-PARAMETERS
  *   dir ... name of directory, without surrounding quotes (e.g. X:\project-xyz)
  *------------------------------------------------------------------------------
  * HISTORY:
  *  Create date (mm/dd/yy):  08/27/13
  *  Last modified date (mm/dd/yy): 
  *  Verison: 1
  *
  *  CHANGE LOG: 
  *
  *   Version   Date       Comment (reference external documentation if available)
  *   -------   --------   --------------------------------------------------------
  *      1      08/08/13   This is a modified version of a macro created and freely
  *                        shared by Adrien Vallee (see below).  The original macro
  *                        has been modified to clear the filref after use.  It  
  *                        also issues abort cancel if dir is blank.
  *                        
  **********************************************************************************/     
  /* Original Author: Adrien Vallee */  
  /* Original Source: http://www.sascommunity.org/wiki/Tips:Check_if_a_directory_exists */
  /* Terms of Use: http://www.sascommunity.org/wiki/sasCommunity:Terms_of_Use */

   %if %length(&dir.) eq 0 %then %do ;
      %put The parameter dir must be non-missing.  ;
      %abort cancel ;
   %end ;
   %local rc fileref return ; 
   %let rc = %qsysfunc(filename(fileref,&dir.)) ; 
   %let return = %qsysfunc(fexist(&fileref.)) ;  
   &return  /* returns value to calling enivornment, like a function */
   %let rc = %qsysfunc(filename(fileref)) ;  
%mend soc_dirExist;


%macro soc_quotepath(list);
  %local j d_exist path_ct path subpath temppath;
  %let list_ct=%qsysfunc(countw(&list,%str( )));
  %do j=1 %to &list_ct.;
    %let subpath=%qscan(&list,&j,%str( ));
    %let d_exist = %soc_dirExist(&subpath) ;  
    %if &d_exist eq 0 %then %do;
      %put Path &subpath does not exist;
      %abort cancel;
    %end;
    %let subpath="&subpath.";
    %let temppath=&temppath. &subpath.;
  %end;
  %let list=%qleft(&temppath);

  &list /* returns value to calling enivornment, like a function */

%mend soc_quotepath;

%macro soc_lib(ref, paths, options=) ;
  /*****************************************************************************
  *                               SENTINEL MACRO
  ******************************************************************************
  * NAME:  soc_lib
  *
  * PURPOSE:  Conditionally assigns a libref with options, if specified, and
  *           aborting if non-missing path is invalid
  *
  * KEY DEPENDENCIES/CONSTRAINTS:  calls macros soc_dirExist and soc_quotePath
  *
  *------------------------------------------------------------------------------
  * USER-PARAMETERS
  *   ref  ... SAS libref-name (e.g. indata) that SAS uses to point to a path
  *   paths ... path-names, deliminated with a single space, without surrounding 
  *             quotes (e.g. X:\project-xyz or /path1/ /path2/)
  *   options ... SAS libname options, with macro-quoting if necessary 
  *               [ e.g. %str(access=readonly) ]
  *------------------------------------------------------------------------------
  * HISTORY:
  *  Create date (mm/dd/yy):  08/27/13
  *  Last modified date (mm/dd/yy): 01/11/19
  *  Verison: 1
  **********************************************************************************/  
  %local libpaths;

  %if %length(&ref) eq 0 %then %do ;
    %put libref is blank ;
     %abort cancel ; 
  %end ;

  %if %length(%superq(paths)) eq 0 %then %do ;
    %put SOC-NOTE: For libref &ref the path is blank, libname assignment skipped ;
  %end ;

  %let libpaths= %soc_quotepath(&paths) ;

  libname &ref. %unquote((&libpaths.)) &options.;
 
 %mend soc_lib;