1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-11 11:00:04 +00:00

fix: linting

This commit is contained in:
2021-04-03 21:30:51 +02:00
parent 096bf4fa11
commit 0a38056c69
88 changed files with 1762 additions and 1468 deletions

View File

@@ -3,7 +3,7 @@
@brief abort gracefully according to context
@details Do not use directly! See bottom of explanation for details.
Configures an abort mechanism according to site specific policies or the
Configures an abort mechanism according to site specific policies or the
particulars of an environment. For instance, can stream custom
results back to the client in an STP Web App context, or completely stop
in the case of a batch run.
@@ -49,7 +49,10 @@
input; putlog _infile_;
i=1;
retain logonce 0;
if (_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR") and logonce=0 then do;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0
then do;
call symputx('logline',_n_);
logonce+1;
end;
@@ -112,21 +115,22 @@
%let syscc=0;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json";
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json";
%let rc=%sysfunc(fcopy(_web,_webout));
%end;
%else %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;

View File

@@ -17,7 +17,7 @@
**/
%macro mf_getattrc(
libds
libds
,attr
)/*/STORE SOURCE*/;
%local dsid rc;

View File

@@ -8,7 +8,7 @@
@param libds library.dataset
@param attr Common values are NLOBS and NVARS, full list in [documentation](
http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000212040.htm)
http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000212040.htm)
@return output returns result of the attrn value supplied, or -1 and log
message if error.
@@ -17,7 +17,7 @@
**/
%macro mf_getattrn(
libds
libds
,attr
)/*/STORE SOURCE*/;
%local dsid rc;

View File

@@ -32,7 +32,9 @@
/* in case the parameter is a libref.tablename, pull off just the libref */
%let libref = %upcase(%scan(&libref, 1, %str(.)));
%let dsid=%sysfunc(open(sashelp.vlibnam(where=(libname="%upcase(&libref)")),i));
%let dsid=%sysfunc(
open(sashelp.vlibnam(where=(libname="%upcase(&libref)")),i)
);
%if (&dsid ^= 0) %then %do;
%let engnum=%sysfunc(varnum(&dsid,ENGINE));
%let rc=%sysfunc(fetch(&dsid));
@@ -41,7 +43,7 @@
%let rc= %sysfunc(close(&dsid));
%end;
&engine
&engine
%mend;

View File

@@ -38,7 +38,7 @@
%let rc=%sysfunc(filename(fref));
%if &format=NO %then %do;
&bytes
&bytes
%end;
%else %do;
%sysfunc(INPUTN(&bytes, best.),sizekmg.)

View File

@@ -16,7 +16,7 @@
%macro mf_getkeyvalue(key,libds=work.mp_setkeyvalue
)/*/STORE SOURCE*/;
%local ds dsid key valc valn type rc;
%local ds dsid key valc valn type rc;
%let dsid=%sysfunc(open(&libds(where=(key="&key"))));
%syscall set(dsid);
%let rc = %sysfunc(fetch(&dsid));

View File

@@ -23,7 +23,7 @@
%local a b c;
%if &switch.NONE=NONE %then %do;
%if %symexist(sysprocessmode) %then %do;
%if "&sysprocessmode"="SAS Object Server"
%if "&sysprocessmode"="SAS Object Server"
or "&sysprocessmode"= "SAS Compute Server" %then %do;
SASVIYA
%end;

View File

@@ -2,7 +2,7 @@
@file
@brief Returns a userid according to session context
@details In a workspace session, a user is generally represented by <code>
&sysuserid</code> or <code>SYS_COMPUTE_SESSION_OWNER</code> if it exists.
&sysuserid</code> or <code>SYS_COMPUTE_SESSION_OWNER</code> if it exists.
In a Stored Process session, <code>&sysuserid</code>
resolves to a system account (default=sassrv) and instead there are several
metadata username variables to choose from (_metauser, _metaperson
@@ -12,7 +12,7 @@
%let user= %mf_getUser();
%put &user;
@param type - do not use, may be deprecated in a future release
@return SYSUSERID (if workspace server)

View File

@@ -20,7 +20,7 @@
%macro mf_getvalue(libds,variable,filter=1
)/*/STORE SOURCE*/;
%if %mf_getattrn(&libds,NLOBS)>0 %then %do;
%if %mf_getattrn(&libds,NLOBS)>0 %then %do;
%local dsid rc &variable;
%let dsid=%sysfunc(open(&libds(where=(&filter))));
%syscall set(dsid);

View File

@@ -5,9 +5,9 @@
Usage:
data test;
format str1 $1. num1 datetime19.;
str2='hello mum!'; num2=666;
stop;
format str1 $1. num1 datetime19.;
str2='hello mum!'; num2=666;
stop;
run;
%put %mf_getVarFormat(test,str1);
%put %mf_getVarFormat(work.test,num1);
@@ -45,9 +45,9 @@
/* Get variable format */
%if(&vnum > 0) %then %let vformat=%sysfunc(varfmt(&dsid, &vnum));
%else %do;
%put NOTE: Variable &var does not exist in &libds;
%let rc = %sysfunc(close(&dsid));
%return;
%put NOTE: Variable &var does not exist in &libds;
%let rc = %sysfunc(close(&dsid));
%return;
%end;
%end;
%else %do;

View File

@@ -5,8 +5,8 @@
Usage:
data test;
format str $1. num datetime19.;
stop;
format str $1. num datetime19.;
stop;
run;
%put %mf_getVarLen(test,str);
%put %mf_getVarLen(work.test,num);
@@ -39,8 +39,8 @@
/* Get variable format */
%if(&vnum > 0) %then %let vlen = %sysfunc(varlen(&dsid, &vnum));
%else %do;
%put NOTE: Variable &var does not exist in &libds;
%let vlen = %str( );
%put NOTE: Variable &var does not exist in &libds;
%let vlen = %str( );
%end;
%end;
%else %put dataset &libds not opened! (rc=&dsid);

View File

@@ -6,8 +6,8 @@
Usage:
data work.test;
format str $1. num datetime19.;
stop;
format str $1. num datetime19.;
stop;
run;
%put %mf_getVarNum(work.test,str);
%put %mf_getVarNum(work.test,num);
@@ -39,8 +39,8 @@ returns:
/* Get variable number */
%let vnum = %sysfunc(varnum(&dsid, &var));
%if(&vnum <= 0) %then %do;
%put NOTE: Variable &var does not exist in &libds;
%let vnum = %str( );
%put NOTE: Variable &var does not exist in &libds;
%let vnum = %str( );
%end;
%end;
%else %put dataset &ds not opened! (rc=&dsid);

View File

@@ -5,8 +5,8 @@
Usage:
data test;
length str $1. num 8.;
stop;
length str $1. num 8.;
stop;
run;
%put %mf_getvartype(test,str);
%put %mf_getvartype(work.test,num);
@@ -35,8 +35,8 @@ Usage:
/* Get variable type (C/N) */
%if(&vnum. > 0) %then %let vtype = %sysfunc(vartype(&dsid, &vnum.));
%else %do;
%put NOTE: Variable &var does not exist in &libds;
%let vtype = %str( );
%put NOTE: Variable &var does not exist in &libds;
%let vtype = %str( );
%end;
%end;
%else %put dataset &libds not opened! (rc=&dsid);

View File

@@ -6,12 +6,13 @@
%sysevalf(%superq(param)=,boolean)
Usage:
%put mf_isblank(&var);
inspiration: https://support.sas.com/resources/papers/proceedings09/022-2009.pdf
%put mf_isblank(&var);
@param param VALUE to be checked
inspiration:
https://support.sas.com/resources/papers/proceedings09/022-2009.pdf
@param param VALUE to be checked
@return output returns 1 (if blank) else 0

View File

@@ -6,7 +6,8 @@
%let isdir=%mf_isdir(/tmp);
With thanks and full credit to Andrea Defronzo - https://www.linkedin.com/in/andrea-defronzo-b1a47460/
With thanks and full credit to Andrea Defronzo -
https://www.linkedin.com/in/andrea-defronzo-b1a47460/
@param path full path of the file/directory to be checked
@@ -17,17 +18,17 @@
%macro mf_isdir(path
)/*/STORE SOURCE*/;
%local rc did is_directory fref_t;
%local rc did is_directory fref_t;
%let is_directory = 0;
%let rc = %sysfunc(filename(fref_t, %superq(path)));
%let did = %sysfunc(dopen(&fref_t.));
%if &did. ^= 0 %then %do;
%let is_directory = 1;
%let rc = %sysfunc(dclose(&did.));
%end;
%let rc = %sysfunc(filename(fref_t));
%let is_directory = 0;
%let rc = %sysfunc(filename(fref_t, %superq(path)));
%let did = %sysfunc(dopen(&fref_t.));
%if &did. ^= 0 %then %do;
%let is_directory = 1;
%let rc = %sysfunc(dclose(&did.));
%end;
%let rc = %sysfunc(filename(fref_t));
&is_directory
&is_directory
%mend;

View File

@@ -46,8 +46,8 @@ Usage:
*/
%if (%length(&dir) gt %length(&child)) %then %do;
%let parent = %substr(&dir, 1, %length(&dir)-%length(&child));
%mf_mkdir(&parent)
%let parent = %substr(&dir, 1, %length(&dir)-%length(&child));
%mf_mkdir(&parent)
%end;
/*
@@ -56,11 +56,11 @@ Usage:
%let dname = %sysfunc(dcreate(&child, &parent));
%if (%bquote(&dname) eq ) %then %do;
%put %str(ERR)OR: could not create &parent + &child;
%abort cancel;
%put %str(ERR)OR: could not create &parent + &child;
%abort cancel;
%end;
%else %do;
%put Directory created: &dir;
%put Directory created: &dir;
%end;
%end;
/* exit quietly if directory did exist.*/

View File

@@ -1,8 +1,9 @@
/**
@file mf_mval.sas
@brief Returns a macro variable value if the variable exists
@details Use this macro to avoid repetitive use of `%if %symexist(MACVAR) %then`
type logic.
@details
Use this macro to avoid repetitive use of `%if %symexist(MACVAR) %then`
type logic.
Usage:
%if %mf_mval(maynotexist)=itdid %then %do;

View File

@@ -1,7 +1,7 @@
/**
@file mf_trimstr.sas
@brief Removes character(s) from the end, if they exist
@details If the designated characters exist at the end of the string, they
@details If the designated characters exist at the end of the string, they
are removed
%put %mf_trimstr(/blah/,/); * /blah;
@@ -12,7 +12,8 @@
@param basestr The string to be modified
@param trimstr The string to be removed from the end of `basestr`, if it exists
@param trimstr The string to be removed from the end of `basestr`, if it
exists
@return output returns result with the value of `trimstr` removed from the end

View File

@@ -35,7 +35,7 @@
%macro mf_verifymacvars(
verifyVars /* list of macro variable NAMES */
verifyVars /* list of macro variable NAMES */
,makeUpcase=NO /* set to YES to make all the variable VALUES uppercase */
,mAbort=SOFT
)/*/STORE SOURCE*/;

View File

@@ -6,7 +6,7 @@
Usage:
%let x= %mf_wordsInStr1ButNotStr2(
Str1=blah sss blaaah brah bram boo
Str1=blah sss blaaah brah bram boo
,Str2= blah blaaah brah ssss
);
@@ -24,8 +24,8 @@
**/
%macro mf_wordsInStr1ButNotStr2(
Str1= /* string containing words to extract */
,Str2= /* used to compare with the extract string */
Str1= /* string containing words to extract */
,Str2= /* used to compare with the extract string */
)/*/STORE SOURCE*/;
%local count_base count_extr i i2 extr_word base_word match outvar;

View File

@@ -6,11 +6,11 @@
results back to the client in an STP Web App context, or completely stop
in the case of a batch run.
Using SAS Abort Cancel mechanisms can cause hung sessions in some Stored Process
environments. This macro takes a unique approach - we set the SAS syscc to 0,
run `stpsrvset('program error', 0)` (if SAS 9) and then - we open a macro
but don't close it! This provides a graceful abort for SAS web services in all
web enabled environments.
Using SAS Abort Cancel mechanisms can cause hung sessions in some Stored
Process environments. This macro takes a unique approach - we set the SAS
syscc to 0, run `stpsrvset('program error', 0)` (if SAS 9) and then - we open
a macro but don't close it! This provides a graceful abort for SAS web
services in all web enabled environments.
@param mac= to contain the name of the calling macro
@param msg= message to be returned
@@ -48,7 +48,10 @@
input; putlog _infile_;
i=1;
retain logonce 0;
if (_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR") and logonce=0 then do;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0 then
do;
call symputx('logline',_n_);
logonce+1;
end;
@@ -129,15 +132,15 @@
%if %symexist(_metaport) %then %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;

View File

@@ -2,9 +2,10 @@
@file
@brief Copy any file using binary input / output streams
@details Reads in a file byte by byte and writes it back out. Is an
os-independent method to copy files. In case of naming collision, the
default filerefs can be modified.
Based on http://stackoverflow.com/questions/13046116/using-sas-to-copy-a-text-file
os-independent method to copy files. In case of naming collision, the
default filerefs can be modified.
Based on:
https://stackoverflow.com/questions/13046116/using-sas-to-copy-a-text-file
%mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout)
@@ -19,12 +20,12 @@
**/
%macro mp_binarycopy(
inloc= /* full path and filename of the object to be copied */
inloc= /* full path and filename of the object to be copied */
,outloc= /* full path and filename of object to be created */
,inref=____in /* override default to use own filerefs */
,outref=____out /* override default to use own filerefs */
)/*/STORE SOURCE*/;
/* these IN and OUT filerefs can point to anything */
/* these IN and OUT filerefs can point to anything */
%if &inref = ____in %then %do;
filename &inref &inloc lrecl=1048576 ;
%end;
@@ -32,20 +33,20 @@
filename &outref &outloc lrecl=1048576 ;
%end;
/* copy the file byte-for-byte */
data _null_;
length filein 8 fileid 8;
filein = fopen("&inref",'I',1,'B');
fileid = fopen("&outref",'O',1,'B');
rec = '20'x;
do while(fread(filein)=0);
rc = fget(filein,rec,1);
rc = fput(fileid, rec);
rc =fwrite(fileid);
end;
rc = fclose(filein);
rc = fclose(fileid);
run;
/* copy the file byte-for-byte */
data _null_;
length filein 8 fileid 8;
filein = fopen("&inref",'I',1,'B');
fileid = fopen("&outref",'O',1,'B');
rec = '20'x;
do while(fread(filein)=0);
rc = fget(filein,rec,1);
rc = fput(fileid, rec);
rc =fwrite(fileid);
end;
rc = fclose(filein);
rc = fclose(fileid);
run;
%if &inref = ____in %then %do;
filename &inref clear;
%end;

View File

@@ -2,10 +2,10 @@
@file mp_cleancsv.sas
@brief Fixes embedded cr / lf / crlf in CSV
@details CSVs will sometimes contain lf or crlf within quotes (eg when
saved by excel). When the termstr is ALSO lf or crlf that can be tricky
to process using SAS defaults.
This macro converts any csv to follow the convention of a windows excel file,
applying CRLF line endings and converting embedded cr and crlf to lf.
saved by excel). When the termstr is ALSO lf or crlf that can be tricky
to process using SAS defaults.
This macro converts any csv to follow the convention of a windows excel file,
applying CRLF line endings and converting embedded cr and crlf to lf.
usage:
@@ -23,7 +23,7 @@
%macro mp_cleancsv(in=NOTPROVIDED,out=NOTPROVIDED,qchar='22'x);
%if "&in"="NOTPROVIDED" or "&out"="NOTPROVIDED" %then %do;
%put %str(ERR)OR: Please provide valid input (&in) and output (&out) locations;
%put %str(ERR)OR: Please provide valid input (&in) & output (&out) locations;
%return;
%end;
@@ -32,9 +32,9 @@
%if %index(&out,.) %then %let out="&out";
/**
* convert all cr and crlf within quotes to lf
* convert all other cr or lf to crlf
*/
* convert all cr and crlf within quotes to lf
* convert all other cr or lf to crlf
*/
data _null_;
infile &in recfm=n ;
file &out recfm=n;

View File

@@ -13,7 +13,7 @@
constraint unq unique(tx_from, dd_type),
constraint nnn not null(DD_SHORTDESC)
);
%mp_getconstraints(lib=work,ds=example,outds=work.constraints)
%mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES)
%mp_createconstraints(inds=work.constraints,outds=created,execute=YES)
@@ -48,7 +48,7 @@ data &outds;
else type=constraint_type;
create_statement=catx(" ","alter table",libref,".",table_name
,"add constraint",constraint_name,type,"(");
if last.constraint_name then
if last.constraint_name then
create_statement=cats(create_statement,column_name,");");
else create_statement=cats(create_statement,column_name,",");
if "&execute"="YES" then call execute(create_statement);

View File

@@ -14,7 +14,7 @@ Usage:
filename ft15f001 temp;
parmcards4;
%* fetch any data from frontend ;
%webout(FETCH)
%webout(FETCH)
data example1 example2;
set sashelp.class;
run;

View File

@@ -62,8 +62,8 @@
%local hasheader; %let hasheader=0;
data _null_;
if _N_ > 1 then do;
call symputx('hasheader',1,'l');
stop;
call symputx('hasheader',1,'l');
stop;
end;
infile &inref;
input;
@@ -131,7 +131,7 @@ run;
/* import the CSV */
data &outds
%if %upcase(&view)=YES %then %do;
/view=&outds
/view=&outds
%end;
;
infile &inref dsd firstobs=2;

View File

@@ -13,7 +13,7 @@
constraint unq unique(tx_from, dd_type),
constraint nnn not null(DD_SHORTDESC)
);
%mp_getconstraints(lib=work,ds=example,outds=work.constraints)
%mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES)

View File

@@ -38,13 +38,13 @@
@returns outds contains the following variables:
- directory (containing folder)
- file_or_folder (file / folder)
- filepath (path/to/file.name)
- filename (just the file name)
- ext (.extension)
- msg (system message if any issues)
- OS SPECIFIC variables, if <code>getattrs=</code> is used.
- directory (containing folder)
- file_or_folder (file / folder)
- filepath (path/to/file.name)
- filename (just the file name)
- ext (.extension)
- msg (system message if any issues)
- OS SPECIFIC variables, if <code>getattrs=</code> is used.
@version 9.2
@author Allan Bowe
@@ -57,8 +57,11 @@
)/*/STORE SOURCE*/;
%let getattrs=%upcase(&getattrs)XX;
data &outds (compress=no keep=file_or_folder filepath filename ext msg directory);
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
data &outds(compress=no
keep=file_or_folder filepath filename ext msg directory
);
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80
ext $20 msg $200;
%if &fref=0 %then %do;
rc = filename(fref, "&path");
%end;
@@ -67,15 +70,15 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg directory
rc=0;
%end;
if rc = 0 then do;
did = dopen(fref);
directory=dinfo(did,'Directory');
if did=0 then do;
putlog "NOTE: This directory is empty - " directory;
msg=sysmsg();
put _all_;
stop;
end;
rc = filename(fref);
did = dopen(fref);
directory=dinfo(did,'Directory');
if did=0 then do;
putlog "NOTE: This directory is empty - " directory;
msg=sysmsg();
put _all_;
stop;
end;
rc = filename(fref);
end;
else do;
msg=sysmsg();
@@ -98,7 +101,7 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg directory
if index(fmsg,'File is in use') or index(dmsg,'is not a directory')
then file_or_folder='file';
else if index(fmsg, 'Insufficient authorization') then file_or_folder='file';
else if index(fmsg,'Insufficient authorization') then file_or_folder='file';
else if file_or_folder='' then file_or_folder='locked';
if file_or_folder='file' then do;

View File

@@ -19,7 +19,7 @@
**/
%macro mp_distinctfmtvalues(
libds=
libds=
,var=
,outvar=formatted_value
,outds=work.mp_distinctfmtvalues
@@ -34,7 +34,7 @@
create table &outds as
select distinct
%if &vtype=C & %trim(&fmt)=%str() %then %do;
&var
&var
%end;
%else %if &vtype=C %then %do;
put(&var,&fmt)
@@ -45,6 +45,6 @@
%else %do;
put(&var,&fmt)
%end;
as &outvar length=&varlen
as &outvar length=&varlen
from &libds;
%mend;

View File

@@ -22,7 +22,7 @@
**/
%macro mp_dropmembers(
list /* space separated list of datasets / views */
list /* space separated list of datasets / views */
,libref=WORK /* can only drop from a single library at a time */
)/*/STORE SOURCE*/;

View File

@@ -10,20 +10,22 @@
, maxobs=5)
TODO:
- labelling the dataset
- explicity setting a unix LF
- constraints / indexes etc
- labelling the dataset
- explicity setting a unix LF
- constraints / indexes etc
@param [in] base_ds= Should be two level - eg work.blah. This is the table that
is converted to a cards file.
@param [in] tgt_ds= Table that the generated cards file would create. Optional -
if omitted, will be same as BASE_DS.
@param [in] base_ds= Should be two level - eg work.blah. This is the table
that is converted to a cards file.
@param [in] tgt_ds= Table that the generated cards file would create.
Optional - if omitted, will be same as BASE_DS.
@param [out] cards_file= Location in which to write the (.sas) cards file
@param [in] maxobs= to limit output to the first <code>maxobs</code> observations
@param [in] showlog= whether to show generated cards file in the SAS log (YES/NO)
@param [in] maxobs= to limit output to the first <code>maxobs</code>
observations
@param [in] showlog= whether to show generated cards file in the SAS log
(YES/NO)
@param [in] outencoding= provide encoding value for file statement (eg utf-8)
@param [in] append= If NO then will rebuild the cards file if it already exists,
otherwise will append to it. Used by the mp_lib2cards.sas macro.
@param [in] append= If NO then will rebuild the cards file if it already
exists, otherwise will append to it. Used by the mp_lib2cards.sas macro.
@version 9.2
@@ -41,8 +43,8 @@
%local i setds nvars;
%if not %sysfunc(exist(&base_ds)) %then %do;
%put WARNING: &base_ds does not exist;
%return;
%put WARNING: &base_ds does not exist;
%return;
%end;
%if %index(&base_ds,.)=0 %then %let base_ds=WORK.&base_ds;
@@ -64,10 +66,12 @@ select count(*) into: nvars from dictionary.columns
%end;
/* get indexes */
proc sort data=sashelp.vindex
(where=(upcase(libname)="%scan(%upcase(&base_ds),1)"
and upcase(memname)="%scan(%upcase(&base_ds),2)"))
out=_data_;
proc sort
data=sashelp.vindex(
where=(upcase(libname)="%scan(%upcase(&base_ds),1)"
and upcase(memname)="%scan(%upcase(&base_ds),2)")
)
out=_data_;
by indxname indxpos;
run;
@@ -82,7 +86,7 @@ data _null_;
idxcnt+1;
nom='';
uni='';
vars=name;
vars=name;
end;
else vars=catx(' ',vars,name);
if last.indxname then do;
@@ -110,8 +114,8 @@ proc sql
;
reset outobs=max;
create table datalines1 as
select name,type,length,varnum,format,label from dictionary.columns
where libname="%upcase(%scan(&base_ds,1))"
select name,type,length,varnum,format,label from dictionary.columns
where libname="%upcase(%scan(&base_ds,1))"
and memname="%upcase(%scan(&base_ds,2))";
/**
@@ -126,7 +130,7 @@ create table datalines1 as
data datalines_2;
format dataline $32000.;
set datalines1 (where=(upcase(name) not in
set datalines1 (where=(upcase(name) not in
('PROCESSED_DTTM','VALID_FROM_DTTM','VALID_TO_DTTM')));
if type='num' then dataline=
cats('ifc(int(',name,')=',name,'
@@ -140,9 +144,9 @@ proc sql noprint;
select dataline into: datalines separated by ',' from datalines_2;
%local
process_dttm_flg
valid_from_dttm_flg
valid_to_dttm_flg
process_dttm_flg
valid_from_dttm_flg
valid_to_dttm_flg
;
%let process_dttm_flg = N;
%let valid_from_dttm_flg = N;
@@ -212,7 +216,7 @@ data _null_;
put "input ";
%do i = 1 %to &nvars.;
%if(%length(&&input_stmt_&i..)) %then
put " &&input_stmt_&i..";
put " &&input_stmt_&i..";
;
%end;
put ";";

View File

@@ -19,8 +19,8 @@
)/*/STORE SOURCE*/;
%if not %sysfunc(exist(&ds)) %then %do;
%put WARNING: &ds does not exist;
%return;
%put WARNING: &ds does not exist;
%return;
%end;
%if %index(&ds,.)=0 %then %let ds=WORK.&ds;
@@ -36,22 +36,22 @@
/* first get headers */
data _null_;
file &outloc dlm=',' dsd &outencoding lrecl=32767;
length header $ 2000;
dsid=open("&ds.","i");
num=attrn(dsid,"nvars");
do i=1 to num;
header = trim(left(coalescec(varlabel(dsid,i),varname(dsid,i))));
put header @;
end;
rc=close(dsid);
file &outloc dlm=',' dsd &outencoding lrecl=32767;
length header $ 2000;
dsid=open("&ds.","i");
num=attrn(dsid,"nvars");
do i=1 to num;
header = trim(left(coalescec(varlabel(dsid,i),varname(dsid,i))));
put header @;
end;
rc=close(dsid);
run;
/* next, export data */
data _null_;
set &ds.;
file &outloc mod dlm=',' dsd &outencoding lrecl=32767;
put (_all_) (+0);
set &ds.;
file &outloc mod dlm=',' dsd &outencoding lrecl=32767;
put (_all_) (+0);
run;

View File

@@ -14,7 +14,7 @@
constraint unq unique(tx_from, dd_type),
constraint nnn not null(DD_SHORTDESC)
);
%mp_getconstraints(lib=work,ds=example,outds=work.constraints)
@param lib= The target library (default=WORK)
@@ -49,8 +49,8 @@ create table &outds as
on a.TABLE_CATALOG=b.TABLE_CATALOG
and a.TABLE_NAME=b.TABLE_NAME
and a.constraint_name=b.constraint_name
where a.TABLE_CATALOG="&lib"
and b.TABLE_CATALOG="&lib"
where a.TABLE_CATALOG="&lib"
and b.TABLE_CATALOG="&lib"
%if "&ds" ne "" %then %do;
and a.TABLE_NAME="&ds"
and b.TABLE_NAME="&ds"

View File

@@ -133,7 +133,9 @@ run;
if notnull='yes' then notnul=' not null';
if notnull='no' and missing(label) then put ' ' name typ;
else if notnull='yes' and missing(label) then put ' ' name typ '[' notnul ']';
else if notnull='yes' and missing(label) then do;
put ' ' name typ '[' notnul ']';
end;
else if notnull='no' then put ' ' name typ '[' lab ']';
else put ' ' name typ '[' notnul ',' lab ']';
@@ -166,7 +168,7 @@ run;
call symputx('constcheck',1);
end;
if last then call symputx('constraints_used',cats(upcase(constraints_used)));
if last then call symput('constraints_used',cats(upcase(constraints_used)));
length curds const col $39;
curds="&curds";
@@ -176,7 +178,8 @@ run;
proc append base=&pkds data=&syslast;run;
/* Create Unique Indexes, but only if they were not already defined within the Constraints section. */
/* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */
data _data_(keep=curds const col);
set &idxinfo (where=(
libname="%scan(&curds,1,.)"
@@ -187,7 +190,7 @@ run;
file &outref mod;
by idxusage indxname;
name=upcase(name);
if &constcheck=1 then stop; /* in fact we only care about PKs so stop if we have */
if &constcheck=1 then stop; /* we only care about PKs so stop if we have */
if _n_=1 and &constcheck=0 then put / ' indexes {';
length cols $5000;
@@ -217,8 +220,8 @@ run;
%end;
/**
* now we need to figure out the relationships
*/
* now we need to figure out the relationships
*/
/* sort alphabetically so we can have one set of unique cols per table */
proc sort data=&pkds nodupkey;
@@ -226,7 +229,7 @@ proc sort data=&pkds nodupkey;
run;
data &pkds.1 (keep=curds col)
&pkds.2 (keep=curds cols);
&pkds.2 (keep=curds cols);
set &pkds;
by curds const;
length retconst $39 cols $5000;
@@ -261,7 +264,11 @@ run;
line='Ref: "'!!"&curds"
!!cats('".(',"%mf_getquotedstr(&pkcols,dlm=%str(,),quote=%str( ))",')')
!!' - '
!!cats(quote(trim(curds)),'.(',"%mf_getquotedstr(&pkcols,dlm=%str(,),quote=%str( ))",')');
!!cats(quote(trim(curds))
,'.('
,"%mf_getquotedstr(&pkcols,dlm=%str(,),quote=%str( ))"
,')'
);
put line;
run;
@@ -282,7 +289,9 @@ run;
create table &pkds.5b as
select curds,count(*) as cnt
from &pkds.5a
where curds not in (select curds from &pkds.2 where cols="&pkcols") /* not a one to one match */
where curds not in (
select curds from &pkds.2 where cols="&pkcols"
) /* not a one to one match */
and curds ne "&curds" /* exclude self */
group by 1;
create table &pkds.6 as

View File

@@ -27,7 +27,7 @@
@param schema= Choose a preferred schema name (default is to use actual schema
,else libref)
@param applydttm= for non SAS DDL, choose if columns are created with native
datetime2 format or regular decimal type
datetime2 format or regular decimal type
@version 9.3
@author Allan Bowe
**/
@@ -86,7 +86,9 @@ create table _data_ as
%global constraints_used;
data _null_;
length ctype $11 constraint_name_orig $256 constraints_used $5000;
set &colconst (where=(table_name="&curds" and constraint_type in ('PRIMARY','UNIQUE'))) end=last;
set &colconst(
where=(table_name="&curds" and constraint_type in ('PRIMARY','UNIQUE'))
) end=last;
file &fref mod;
by constraint_type constraint_name;
retain constraints_used;
@@ -161,10 +163,19 @@ run;
put ');';
run;
/* Create Unique Indexes, but only if they were not already defined within the Constraints section. */
/* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */
data _null_;
*length ds $128;
set &idxinfo (where=(memname="&curds" and unique='yes' and indxname not in (%sysfunc(tranwrd("&constraints_used",%str( ),%str(","))))));
set &idxinfo(
where=(
memname="&curds"
and unique='yes'
and indxname not in (
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
)
)
);
file &fref mod;
by idxusage indxname;
/* ds=cats(libname,'.',memname); */
@@ -228,10 +239,19 @@ run;
/* Extra step for data constraints */
%addConst()
/* Create Unique Indexes, but only if they were not already defined within the Constraints section. */
/* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */
data _null_;
*length ds $128;
set &idxinfo (where=(memname="&curds" and unique='yes' and indxname not in (%sysfunc(tranwrd("&constraints_used",%str( ),%str(","))))));
set &idxinfo(
where=(
memname="&curds"
and unique='yes'
and indxname not in (
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
)
)
);
file &fref mod;
by idxusage indxname;
*ds=cats(libname,'.',memname);
@@ -320,15 +340,24 @@ run;
put ');';
run;
/* Create Unique Indexes, but only if they were not already defined within the Constraints section. */
/* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */
data _null_;
*length ds $128;
set &idxinfo (where=(memname="&curds" and unique='yes' and indxname not in (%sysfunc(tranwrd("&constraints_used",%str( ),%str(","))))));
set &idxinfo(
where=(
memname="&curds"
and unique='yes'
and indxname not in (
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
)
)
);
file &fref mod;
by idxusage indxname;
/* ds=cats(libname,'.',memname); */
if first.indxname then do;
put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds (" ;
put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds(";
put ' "' name +(-1) '"' ;
end;
else put ' ,"' name +(-1) '"';

View File

@@ -1,17 +1,18 @@
/**
@file mp_getmaxvarlengths.sas
@brief Scans a dataset to find the max length of the variable values
@details
@details
This macro will scan a base dataset and produce an output dataset with two
columns:
- NAME Name of the base dataset column
- MAXLEN Maximum length of the data contained therein.
Character fields may be allocated very large widths (eg 32000) of which the maximum
value is likely to be much narrower. This macro was designed to enable a HTML
table to be appropriately sized however this could be used as part of a data
audit to ensure we aren't over-sizing our tables in relation to the data therein.
Character fields may be allocated very large widths (eg 32000) of which the
maximum value is likely to be much narrower. This macro was designed to
enable a HTML table to be appropriately sized however this could be used as
part of a data audit to ensure we aren't over-sizing our tables in relation to
the data therein.
Numeric fields are converted using the relevant format to determine the width.
Usage:
@@ -33,7 +34,7 @@
%macro mp_getmaxvarlengths(
libds /* libref.dataset to analyse */
,outds=work.mp_getmaxvarlengths /* name of output dataset to create */
,outds=work.mp_getmaxvarlengths /* name of output dataset to create */
)/*/STORE SOURCE*/;
%local vars x var fmt;

View File

@@ -4,8 +4,8 @@
@details PROC JSON is faster but will produce errs like the ones below if
special chars are encountered.
>An object or array close is not valid at this point in the JSON text.
>Date value out of range
>An object or array close is not valid at this point in the JSON text.
>Date value out of range
If this happens, try running with ENGINE=DATASTEP.
@@ -13,7 +13,7 @@
filename tmp temp;
data class; set sashelp.class;run;
%mp_jsonout(OBJ,class,jref=tmp)
data _null_;
@@ -22,7 +22,7 @@
run;
If you are building web apps with SAS then you are strongly encouraged to use
the mX_createwebservice macros in combination with the
the mX_createwebservice macros in combination with the
[sasjs adapter](https://github.com/sasjs/adapter).
For more information see https://sasjs.io
@@ -38,11 +38,11 @@
@param fmt= Whether to keep or strip formats from the table
@param engine= Which engine to use to send the JSON, options are:
* PROCJSON (default)
* DATASTEP
* DATASTEP
@param dbg= DEPRECATED - was used to conditionally add PRETTY to
proc json but this can cause line truncation in large files.
@version 9.2
@author Allan Bowe
@@ -66,7 +66,7 @@
%if &engine=PROCJSON %then %do;
data;run;%let tempds=&syslast;
proc sql;drop table &tempds;
data &tempds /view=&tempds;set &ds;
data &tempds /view=&tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;;
proc json out=&jref pretty
%if &action=ARR %then nokeys ;
@@ -81,13 +81,14 @@
%put &sysmacroname: &ds NOT FOUND!!!;
%return;
%end;
data _null_;file &jref mod ;
data _null_;file &jref mod ;
put "["; call symputx('cols',0,'l');
proc sort data=sashelp.vcolumn(where=(libname='WORK' & memname="%upcase(&ds)"))
proc sort
data=sashelp.vcolumn(where=(libname='WORK' & memname="%upcase(&ds)"))
out=_data_;
by varnum;
data _null_;
data _null_;
set _last_ end=last;
call symputx(cats('name',_n_),name,'l');
call symputx(cats('type',_n_),type,'l');
@@ -121,8 +122,9 @@
)))))!!'"';
%end;
%end;
run;
/* write to temp loc to avoid _webout truncation - https://support.sas.com/kb/49/325.html */
run;
/* write to temp loc to avoid _webout truncation
- https://support.sas.com/kb/49/325.html */
filename _sjs temp lrecl=131068 encoding='utf-8';
data _null_; file _sjs lrecl=131068 encoding='utf-8' mod;
set &tempds;
@@ -131,7 +133,7 @@
%do i=1 %to &cols;
%if &i>1 %then "," ;
%if &action=OBJ %then """&&name&i"":" ;
&&name&i
&&name&i
%end;
%if &action=ARR %then "]" ; %else "}" ; ;
proc sql;

View File

@@ -16,13 +16,13 @@
%mp_prevobs(INIT,history=2)
if _n_ =10 then do;
%* fetch previous but 1 record;
%mp_prevobs(FETCH,-2)
put _n_= name= age= calc_var=;
%mp_prevobs(FETCH,-2)
put _n_= name= age= calc_var=;
%* fetch previous record;
%mp_prevobs(FETCH,-1)
put _n_= name= age= calc_var=;
%mp_prevobs(FETCH,-1)
put _n_= name= age= calc_var=;
%* reinstate current record ;
%mp_prevobs(FETCH,0)
%mp_prevobs(FETCH,0)
put _n_= name= age= calc_var=;
end;
run;
@@ -35,11 +35,11 @@
https://www.lexjansen.com/pharmasug/2008/cc/CC08.pdf
@param action Either FETCH a current or previous record, or INITialise.
@param record The relative (to current) position of the previous observation
to return.
@param record The relative (to current) position of the previous observation
to return.
@param history= The number of records to retain in the hash table. Default=5
@param prefix= the prefix to give to the variables used to store the hash name
and index. Default=mp_prevobs
and index. Default=mp_prevobs
@version 9.2
@author Allan Bowe
@@ -53,33 +53,33 @@
%let record=%eval((&record+0) * -1);
%if &action=INIT %then %do;
if _n_ eq 1 then do;
attrib &prefix._VAR length=$64;
if _n_ eq 1 then do;
attrib &prefix._VAR length=$64;
dcl hash &prefix._HASH(ordered:'Y');
&prefix._KEY=0;
&prefix._HASH.defineKey("&prefix._KEY");
do while(1);
call vnext(&prefix._VAR);
&prefix._HASH.defineKey("&prefix._KEY");
do while(1);
call vnext(&prefix._VAR);
if &prefix._VAR='' then leave;
if &prefix._VAR eq "&prefix._VAR" then continue;
else if &prefix._VAR eq "&prefix._KEY" then continue;
if &prefix._VAR eq "&prefix._VAR" then continue;
else if &prefix._VAR eq "&prefix._KEY" then continue;
&prefix._HASH.defineData(&prefix._VAR);
end;
&prefix._HASH.defineDone();
end;
&prefix._HASH.defineDone();
end;
/* this part has to happen before FETCHing */
&prefix._KEY+1;
&prefix._rc=&prefix._HASH.add();
if &prefix._rc then putlog 'adding' &prefix._rc=;
%if &history>0 %then %do;
if &prefix._key>&history+1 then
if &prefix._key>&history+1 then
&prefix._HASH.remove(key: &prefix._KEY - &history - 1);
if &prefix._rc then putlog 'removing' &prefix._rc=;
%end;
%end;
%else %if &action=FETCH %then %do;
if &record > &prefix._key then putlog "Not enough records in &Prefix._hash yet";
if &record>&prefix._key then putlog "Not enough records in &Prefix._hash yet";
else &prefix._rc=&prefix._HASH.find(key: &prefix._KEY - &record);
if &prefix._rc then putlog &prefix._rc= " when fetching " &prefix._KEY=
"with record &record and " _n_=;

View File

@@ -32,9 +32,9 @@
@returns outds contains the following variables:
- level (0 = top level)
- &parentvar
- &childvar (null if none found)
- level (0 = top level)
- &parentvar
- &childvar (null if none found)
@version 9.2
@author Allan Bowe

View File

@@ -8,14 +8,14 @@
rootlib
|-- LIBREF1
| |__ mytable.ddl
| |__ someothertable.ddl
| |__ mytable.ddl
| |__ someothertable.ddl
|-- LIBREF2
| |__ table1.ddl
| |__ table2.ddl
| |__ table1.ddl
| |__ table2.ddl
|-- LIBREF3
|__ table3.ddl
|__ table4.ddl
|__ table3.ddl
|__ table4.ddl
Only files with the .ddl suffix are executed. The parent folder name is used
as the libref.

View File

@@ -32,7 +32,7 @@ create table _data_ as
where upcase(libname) in ("IMPOSSIBLE",
%local x;
%do x=1 %to %sysfunc(countw(&libs));
"%upcase(%scan(&libs,&x))"
"%upcase(%scan(&libs,&x))"
%end;
)
%end;

View File

@@ -3,7 +3,7 @@
@brief Searches all data in a library
@details
Scans an entire library and creates a copy of any table
containing a specific string OR numeric value. Only
containing a specific string OR numeric value. Only
matching records are written out.
If both a string and numval are provided, the string
will take precedence.
@@ -20,9 +20,10 @@
@param ds= the dataset to search (leave blank to search entire library)
@param string= the string value to search
@param numval= the numeric value to search (must be exact)
@param outloc= the directory in which to create the output datasets with matching
rows. Will default to a subfolder in the WORK library.
@param outobs= set to a positive integer to restrict the number of observations
@param outloc= the directory in which to create the output datasets with
matching rows. Will default to a subfolder in the WORK library.
@param outobs= set to a positive integer to restrict the number of
observations
@param filter_text= add a (valid) filter clause to further filter the results
<h4> SAS Macros </h4>
@@ -36,7 +37,7 @@
**/
%macro mp_searchdata(lib=sashelp
,ds=
,ds=
,string= /* the query will use a contains (?) operator */
,numval= /* numeric must match exactly */
,outloc=%sysfunc(pathname(work))/mpsearch
@@ -44,7 +45,8 @@
,filter_text=%str(1=1)
)/*/STORE SOURCE*/;
%local table_list table table_num table colnum col start_tm check_tm vars type coltype;
%local table_list table table_num table colnum col start_tm check_tm vars type
coltype;
%put process began at %sysfunc(datetime(),datetime19.);
%if &syscc ge 4 %then %do;
@@ -61,14 +63,14 @@ libname mpsearch "&outloc";
/* get the list of tables in the library */
proc sql noprint;
select distinct memname into: table_list separated by ' '
from dictionary.tables
from dictionary.tables
where upcase(libname)="%upcase(&lib)"
%if &ds ne %then %do;
and upcase(memname)=%upcase("&ds")
%end;
;
/* check that we have something to check */
proc sql
proc sql
%if &outobs>-1 %then %do;
outobs=&outobs
%end;
@@ -85,7 +87,7 @@ proc sql
%let check_tm=%sysfunc(datetime());
/* build sql statement */
create table mpsearch.&table as select * from &lib..&table
where %unquote(&filter_text) and
where %unquote(&filter_text) and
(0
/* loop through columns */
%do colnum=1 %to %sysfunc(countw(&vars,%str( )));
@@ -101,7 +103,8 @@ proc sql
%end;
%end;
);
%put Search query for &table took %sysevalf(%sysfunc(datetime())-&check_tm) seconds;
%put Search query for &table took
%sysevalf(%sysfunc(datetime())-&check_tm) seconds;
%if &sqlrc ne 0 %then %do;
%put %str(WAR)NING: SQLRC=&sqlrc when processing &table;
%return;

View File

@@ -12,7 +12,7 @@
@param key Provide a key on which to perform the lookup
@param value Provide a value
@param type= either C or N will populate valc and valn respectively. C is
default.
default.
@param libds= define the target table to hold the parameters
@version 9.2

View File

@@ -1,12 +1,13 @@
/**
@file
@brief Capture session start / finish times and request details
@details For details, see http://www.rawsas.com/2015/09/logging-of-stored-process-server.html.
@details For details, see
https://rawsas.com/event-logging-of-stored-process-server-sessions.
Requires a base table in the following structure (name can be changed):
proc sql;
create table &libds(
request_dttm num not null format=datetime.
request_dttm num not null format=datetime.
,status_cd char(4) not null
,_metaperson varchar(100) not null
,_program varchar(500)

View File

@@ -6,7 +6,8 @@
Usage:
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@@ -65,13 +66,15 @@
%else %if &contentype=XLSX %then %do;
%if &platform=SASMETA %then %do;
data _null_;
rc=stpsrv_header('Content-type','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
rc=stpsrv_header('Content-type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%else %if &platform=SASVIYA %then %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
contenttype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
contenttype=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
contentdisp="attachment; filename=&outname";
%end;
%end;
@@ -113,10 +116,10 @@
%end;
%if &inref ne 0 %then %do;
%mp_binarycopy(inref=&inref,outref=_webout)
%mp_binarycopy(inref=&inref,outref=_webout)
%end;
%else %do;
%mp_binarycopy(inloc="&inloc",outref=_webout)
%mp_binarycopy(inloc="&inloc",outref=_webout)
%end;
%mend;

View File

@@ -5,7 +5,7 @@
testing of arbitrary jobs.
%mp_testjob(
duration=60*5
duration=60*5
)
@param [in] duration= the time in seconds which the job should run for. Actual

View File

@@ -1,10 +1,10 @@
/**
@file mp_testwritespeedlibrary.sas
@brief Tests the write speed of a new table in a SAS library
@details Will create a new table of a certain size in an
@details Will create a new table of a certain size in an
existing SAS library. The table will have one column,
and will be subsequently deleted.
%mp_testwritespeedlibrary(
lib=work
,size=0.5

View File

@@ -8,8 +8,11 @@
Credits:
* Roger Deangelis, https://communities.sas.com/t5/SAS-Programming/listing-all-files-within-a-directory-and-subdirectories/m-p/332616/highlight/true#M74887
* Tom, https://communities.sas.com/t5/SAS-Programming/listing-all-files-of-all-types-from-all-subdirectories/m-p/334113/highlight/true#M75419
Roger Deangelis:
https://communities.sas.com/t5/SAS-Programming/listing-all-files-within-a-directory-and-subdirectories/m-p/332616/highlight/true#M74887
Tom:
https://communities.sas.com/t5/SAS-Programming/listing-all-files-of-all-types-from-all-subdirectories/m-p/334113/highlight/true#M75419
@param dir= Directory to be scanned (default=/tmp)
@@ -17,13 +20,13 @@
@returns outds contains the following variables:
- `dir`: a flag (1/0) to say whether it is a directory or not. This is not
reliable - folders that you do not have permission to open will be flagged
as directories.
- `ext`: file extension
- `filename`: file name
- `dirname`: directory name
- `fullpath`: directory + file name
- `dir`: a flag (1/0) to say whether it is a directory or not. This is not
reliable - folders that you do not have permission to open will be flagged
as directories.
- `ext`: file extension
- `filename`: file name
- `dirname`: directory name
- `fullpath`: directory + file name
@version 9.2
**/