diff --git a/README.md b/README.md
index 3fc74f0..4c5bf7f 100644
--- a/README.md
+++ b/README.md
@@ -31,14 +31,14 @@ Documentation: https://core.sasjs.io
## Components
-### BASE library (All Platforms)
+### BASE folder (All Platforms)
- OS independent
- Works on all SAS Platforms
- No X command
- Prefixes: _mf_, _mp_
-### DDL library (All Platforms)
+### DDL folder (All Platforms)
- OS independent
- Works on all SAS Platforms
@@ -47,45 +47,13 @@ Documentation: https://core.sasjs.io
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
-### FCMP library (All Platforms)
+### FCMP folder (All Platforms)
- Function and macro names are identical, except for special cases
- Prefixes: _mcf_
The fcmp macros are used to generate fcmp functions, and can be used with or without the `proc fcmp` wrapper.
-### META library (SAS9 only)
-
-Macros used in SAS EBI, which connect to the metadata server.
-
-- OS independent
-- Metadata aware
-- No X command
-- Prefixes: _mm_
-
-### SERVER library (@sasjs/server only)
-These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
-
-- OS independent
-- @sasjs/server aware
-- No X command
-- Prefixes: _ms_
-
-### VIYA library (Viya only)
-
-Macros used for interfacing with SAS Viya.
-
-- OS independent
-- No X command
-- Prefixes: _mv_, _mvf_
-
-### METAX library (SAS9 only)
-
-- OS specific
-- Metadata aware
-- X command enabled
-- Prefixes: _mmw_,_mmu_,_mmx_
-
### LUA library
Wait - this is a macro library - what is LUA doing here? Well, it is a little known fact that you CAN run LUA within a SAS Macro. It has to be written to a text file with a `.lua` extension, from where you can `%include` it. So, without using the `proc lua` wrapper.
@@ -106,13 +74,61 @@ run;
- Prefixes: _ml_
+### META folder (SAS9 only)
+
+Macros used in SAS EBI, which connect to the metadata server.
+
+- OS independent
+- Metadata aware
+- No X command
+- Prefixes: _mm_
+
+### METAX folder (SAS9 only)
+
+- OS specific
+- Metadata aware
+- X command enabled
+- Prefixes: _mmw_,_mmu_,_mmx_
+
+### SERVER folder (@sasjs/server only)
+These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
+
+- OS independent
+- @sasjs/server aware
+- No X command
+- Prefixes: _ms_
+
+### VIYA folder (Viya only)
+
+Macros used for interfacing with SAS Viya.
+
+- OS independent
+- No X command
+- Prefixes: _mv_, _mvf_
+
+### XPLATFORM folder (Viya, Meta, and Server)
+
+Sometimes it is helpful to use a macro that can be used interchangeably regardless of the server type on which is is running (SASVIYA, SAS9, SASJS).
+
+- OS independent
+- No X command
+- Prefixes: _mx_
+
## Installation
First, download the repo to a location your SAS system can access. Then update your sasautos path to include the components you wish to have available, eg:
```sas
-options insert=(sasautos="/your/path/macrocore/base");
-options insert=(sasautos="/your/path/macrocore/meta");
+%let repoloc=/your/path/core;
+options insert=(sasautos="&repoloc/base");
+options insert=(sasautos="&repoloc/ddl");
+options insert=(sasautos="&repoloc/fcmp");
+options insert=(sasautos="&repoloc/lua");
+options insert=(sasautos="&repoloc/meta");
+options insert=(sasautos="&repoloc/metax");
+options insert=(sasautos="&repoloc/server");
+options insert=(sasautos="&repoloc/viya");
+options insert=(sasautos="&repoloc/xplatform");
```
The above can be done directly in your sas program, via an autoexec, or an initialisation program.
@@ -142,7 +158,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
- _mp_ for macro procedures (which generate sas code)
- _ms_ for macro procedures that will only work with [@sasjs/server](https://github.com/sasjs/server)
- _mv_ for macro procedures that will only work in Viya
- - _mx_ for macros that are XCMD enabled (working on both windows and unix)
+ - _mx_ for macros that work on Viya, SAS 9 EBI and SASjs Server
- follow verb-noun convention
- unix style line endings (lf)
- individual lines should be no more than 80 characters long
diff --git a/base/mf_getplatform.sas b/base/mf_getplatform.sas
index 4d20dbd..8416686 100644
--- a/base/mf_getplatform.sas
+++ b/base/mf_getplatform.sas
@@ -5,8 +5,12 @@
%put %mf_getplatform();
- returns:
- SASMETA (or SASVIYA)
+ returns one of:
+
+ @li SASMETA
+ @li SASVIYA
+ @li SASJS
+ @li BASESAS
@param switch the param for which to return a platform specific variable
@@ -68,4 +72,4 @@
%else %if &switch=VIYARESTAPI %then %do;
%mf_trimstr(%sysfunc(getoption(servicesbaseurl)),/)
%end;
-%mend mf_getplatform;
\ No newline at end of file
+%mend mf_getplatform;
diff --git a/base/mf_isint.sas b/base/mf_isint.sas
index 71548bb..a6019a1 100644
--- a/base/mf_isint.sas
+++ b/base/mf_isint.sas
@@ -33,4 +33,4 @@
%if %sysfunc(findc(%str(&val),,kd)) %then %do;0%end;
%else %do;1%end;
-%mend mf_isint;
\ No newline at end of file
+%mend mf_isint;
diff --git a/base/mp_createwebservice.sas b/base/mp_createwebservice.sas
index 80b4459..4be9b08 100644
--- a/base/mp_createwebservice.sas
+++ b/base/mp_createwebservice.sas
@@ -1,50 +1,13 @@
/**
@file mp_createwebservice.sas
- @brief Create a web service in SAS 9 or Viya
- @details Creates a SASJS ready Stored Process in SAS 9 or Job Execution
- Service in SAS Viya
+ @brief Create a web service in SAS 9, Viya or SASjs Server
+ @details This is actually a wrapper for mx_createwebservice.sas, remaining
+ for legacy purposes. For new apps, use mx_createwebservice.sas.
-Usage:
-
- %* compile macros ;
- filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
- %inc mc;
-
- %* write some code;
- filename ft15f001 temp;
- parmcards4;
- %* fetch any data from frontend ;
- %webout(FETCH)
- data example1 example2;
- set sashelp.class;
- run;
- %* send data back;
- %webout(OPEN)
- %webout(ARR,example1) * Array format, fast, suitable for large tables ;
- %webout(OBJ,example2) * Object format, easier to work with ;
- %webout(CLOSE)
- ;;;;
- %mp_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
SAS Macros
- @li mf_getplatform.sas
- @li mm_createwebservice.sas
- @li ms_createwebservice.sas
- @li mv_createwebservice.sas
+ @li mx_createwebservice.sas
- @param [in,out] path= The full folder path where the service will be created
- @param [in,out] name= Service name. Avoid spaces.
- @param [in] desc= The description of the service (optional)
- @param [in] precode= Space separated list of filerefs, pointing to the code
- that needs to be attached to the beginning of the service (optional)
- @param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
- be added
- @param [in] replace= (YES) Select YES to replace any existing service in that
- location
- @param [in] mDebug= (0) set to 1 to show debug messages in the log
-
- @version 9.2
- @author Allan Bowe
**/
@@ -57,40 +20,13 @@ Usage:
,mdebug=0
)/*/STORE SOURCE*/;
-%if &syscc ge 4 %then %do;
- %put syscc=&syscc - &sysmacroname will not execute in this state;
- %return;
-%end;
-
-%local platform; %let platform=%mf_getplatform();
-%if &platform=SASVIYA %then %do;
- %if "&path"="HOME" %then %let path=/Users/&sysuserid/My Folder;
- %mv_createwebservice(path=&path
+ %mx_createwebservice(path=&path
,name=&name
- ,code=&code
,precode=&precode
+ ,code=&code
,desc=&desc
,replace=&replace
- )
-%end;
-%else %if &platform=SASJS %then %do;
- %if "&path"="HOME" %then %let path=/Users/&_sasjs_username/My Folder;
- %ms_createwebservice(path=&path
- ,name=&name
- ,code=&code
- ,precode=&precode
,mdebug=&mdebug
)
-%end;
-%else %do;
- %if "&path"="HOME" %then %let path=/User Folders/&_METAPERSON/My Folder;
- %mm_createwebservice(path=&path
- ,name=&name
- ,code=&code
- ,precode=&precode
- ,desc=&desc
- ,replace=&replace
- )
-%end;
%mend mp_createwebservice;
diff --git a/base/mp_testservice.sas b/base/mp_testservice.sas
index c21e0a2..49c6f64 100644
--- a/base/mp_testservice.sas
+++ b/base/mp_testservice.sas
@@ -1,53 +1,11 @@
/**
@file
- @brief Will execute a SASjs web service on SAS 9 or Viya
- @details Prepares the input files and retrieves the resulting datasets from
- the response JSON.
-
-
-
- Note - the _webout fileref should NOT be assigned prior to running this macro.
-
- @param [in] program The _PROGRAM endpoint to test
- @param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
- follows:
- inputfiles=inref:filename inref2:filename2
- @param [in] inputdatasets= (0) All datasets in this space seperated list are
- converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to
- the list of `inputfiles` for ingestion. The dataset will be sent with the
- same name (no need for a colon modifier).
- @param [in] inputparams=(0) A dataset containing name/value pairs in the
- following format:
- |name:$32|value:$1000|
- |---|---|
- |stpmacname|some value|
- |mustbevalidname|can be anything, oops, %abort!!|
-
- @param [in] debug= (log) Provide the _debug value
- @param [in] mdebug= (0) Set to 1 to provide macro debugging
- @param [in] viyaresult= (WEBOUT_JSON) The Viya result type to return. For
- more info, see mv_getjobresult.sas
- @param [in] viyacontext= (SAS Job Execution compute context) The Viya compute
- context on which to run the service
- @param [out] outlib= (0) Output libref to contain the final tables. Set to
- 0 if the service output is not in JSON format.
- @param [out] outref= (0) Output fileref to create, to contain the full _webout
- response.
+ @brief To be deprecated. Will execute a SASjs web service on SAS 9 or Viya
+ @details Use the mx_testservice.sas macro instead (documentation can be
+ found there)
SAS Macros
- @li mf_getplatform.sas
- @li mf_getuniquefileref.sas
- @li mf_getuniquename.sas
- @li mp_abort.sas
- @li mp_binarycopy.sas
- @li mp_chop.sas
- @li mp_ds2csv.sas
- @li ms_testservice.sas
- @li mv_getjobresult.sas
- @li mv_jobflow.sas
-
- Related Programs
- @li mp_testservice.test.sas
+ @li mx_testservice.sas
@version 9.4
@author Allan Bowe
@@ -65,237 +23,17 @@
viyaresult=WEBOUT_JSON,
viyacontext=SAS Job Execution compute context
)/*/STORE SOURCE*/;
-%local dbg pcnt fref1 fref2 webref webrefpath i webcount var platform;
-%if &mdebug=1 %then %do;
- %put &sysmacroname entry vars:;
- %put _local_;
-%end;
-%else %let dbg=*;
-/* sanitise inputparams */
-%let pcnt=0;
-%if &inputparams ne 0 %then %do;
- data _null_;
- set &inputparams;
- if not nvalid(name,'v7') then putlog (_all_)(=);
- else if name in (
- 'program','inputfiles','inputparams','debug','outlib','outref'
- ) then putlog (_all_)(=);
- else do;
- x+1;
- call symputx(name,quote(cats(value)),'l');
- call symputx(cats('pval',x),name,'l');
- call symputx('pcnt',x,'l');
- end;
- run;
- %mp_abort(iftrue= (%mf_nobs(&inputparams) ne &pcnt)
- ,mac=&sysmacroname
- ,msg=%str(Invalid values in &inputparams)
- )
-%end;
+%mx_testservice(&program,
+ inputfiles=&inputfiles,
+ inputdatasets=&inputdatasets,
+ inputparams=&inputparams,
+ debug=&debug,
+ mdebug=&mdebug,
+ outlib=&outlib,
+ outref=&outref,
+ viyaresult=&viyaresult,
+ viyacontext=&viyacontext
+)
-/* convert inputdatasets to filerefs */
-%if "&inputdatasets" ne "0" %then %do;
- %if %quote(&inputfiles)=0 %then %let inputfiles=;
- %do i=1 %to %sysfunc(countw(&inputdatasets,%str( )));
- %let var=%scan(&inputdatasets,&i,%str( ));
- %local dsref&i;
- %let dsref&i=%mf_getuniquefileref();
- %mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS)
- %let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.);
- %end;
-%end;
-
-%let platform=%mf_getplatform();
-%let fref1=%mf_getuniquefileref();
-%let fref2=%mf_getuniquefileref();
-%let webref=%mf_getuniquefileref();
-%let webrefpath=%sysfunc(pathname(work))/%mf_getuniquename();
-/* mp_chop requires a physical path as input */
-filename &webref "&webrefpath";
-
-%if &platform=SASMETA %then %do;
-
- /* parse the input files */
- %if %quote(&inputfiles) ne 0 %then %do;
- %let webcount=%sysfunc(countw(&inputfiles));
- %put &=webcount;
- %do i=1 %to &webcount;
- %let var=%scan(&inputfiles,&i,%str( ));
- %local webfref&i webname&i;
- %let webref&i=%scan(&var,1,%str(:));
- %let webname&i=%scan(&var,2,%str(:));
- %put webref&i=&&webref&i;
- %put webname&i=&&webname&i;
- %end;
- %end;
- %else %let webcount=0;
-
- proc stp program="&program";
- inputparam _program="&program"
- %do i=1 %to &webcount;
- %if &webcount=1 %then %do;
- _webin_fileref="&&webref&i"
- _webin_name="&&webname&i"
- %end;
- %else %do;
- _webin_fileref&i="&&webref&i"
- _webin_name&i="&&webname&i"
- %end;
- %end;
- _webin_file_count="&webcount"
- _debug="&debug"
- %do i=1 %to &pcnt;
- /* resolve name only, proc stp fetches value */
- &&pval&i=&&&&&&pval&i
- %end;
- ;
- %do i=1 %to &webcount;
- inputfile &&webref&i;
- %end;
- outputfile _webout=&webref;
- run;
-
- data _null_;
- infile &webref;
- file &fref1;
- input;
- length line $10000;
- if index(_infile_,'>>weboutBEGIN<<') then do;
- line=tranwrd(_infile_,'>>weboutBEGIN<<','');
- put line;
- end;
- else if index(_infile_,'>>weboutEND<<') then do;
- line=tranwrd(_infile_,'>>weboutEND<<','');
- put line;
- stop;
- end;
- else put _infile_;
- run;
- data _null_;
- infile &fref1;
- input;
- put _infile_;
- run;
- %if &outlib ne 0 %then %do;
- libname &outlib json (&fref1);
- %end;
- %if &outref ne 0 %then %do;
- filename &outref temp;
- %mp_binarycopy(inref=&webref,outref=&outref)
- %end;
-
-%end;
-%else %if &platform=SASVIYA %then %do;
-
- /* prepare inputparams */
- %local ds1;
- %let ds1=%mf_getuniquename();
- %if "&inputparams" ne "0" %then %do;
- proc transpose data=&inputparams out=&ds1;
- id name;
- var value;
- run;
- %end;
- %else %do;
- data &ds1;run;
- %end;
-
- /* parse the input files - convert to sasjs params */
- %local webcount i var sasjs_tables;
- %if %quote(&inputfiles) ne 0 %then %do;
- %let webcount=%sysfunc(countw(&inputfiles));
- %put &=webcount;
- %do i=1 %to &webcount;
- %let var=%scan(&inputfiles,&i,%str( ));
- %local webfref&i webname&i sasjs&i.data;
- %let webref&i=%scan(&var,1,%str(:));
- %let webname&i=%scan(&var,2,%str(:));
- %put webref&i=&&webref&i;
- %put webname&i=&&webname&i;
-
- %let sasjs_tables=&sasjs_tables &&webname&i;
- data _null_;
- infile &&webref&i lrecl=32767;
- input;
- if _n_=1 then call symputx("sasjs&i.data",_infile_);
- else call symputx(
- "sasjs&i.data",cats(symget("sasjs&i.data"),'0D0A'x,_infile_)
- );
- putlog "&sysmacroname infile: " _infile_;
- run;
- data &ds1;
- set &ds1;
- length sasjs&i.data $32767 sasjs_tables $1000;
- sasjs&i.data=symget("sasjs&i.data");
- sasjs_tables=symget("sasjs_tables");
- run;
- %end;
- %end;
- %else %let webcount=0;
-
- data &ds1;
- retain _program "&program";
- retain _contextname "&viyacontext";
- set &ds1;
- putlog "&sysmacroname inputparams:";
- putlog (_all_)(=);
- run;
-
- %mv_jobflow(inds=&ds1
- ,maxconcurrency=1
- ,outds=work.results
- ,outref=&fref1
- ,mdebug=&mdebug
- )
- /* show the log */
- data _null_;
- infile &fref1;
- input;
- putlog _infile_;
- run;
- /* get the uri to fetch results */
- data _null_;
- set work.results;
- call symputx('uri',uri);
- putlog "&sysmacroname: fetching results for " uri;
- run;
- /* fetch results from webout.json */
- %mv_getjobresult(uri=&uri,
- result=&viyaresult,
- outref=&outref,
- outlib=&outlib,
- mdebug=&mdebug
- )
-
-%end;
-%else %if &platform=SASJS %then %do;
-
- %ms_testservice(&program
- ,inputfiles=&inputfiles
- ,inputdatasets=&inputdatasets
- ,inputparams=&inputparams
- ,debug=&debug
- ,mdebug=&mdebug
- ,outlib=&outlib
- ,outref=&outref
- )
-
-%end;
-%else %do;
- %put %str(ERR)OR: Unrecognised platform: &platform;
-%end;
-
-%if &mdebug=0 %then %do;
- filename &fref1 clear;
- %if &platform ne SASJS %then %do;
- filename &fref2 clear;
- filename &webref clear;
- %end;
-%end;
-%else %do;
- %put &sysmacroname exit vars:;
- %put _local_;
-%end;
-
-%mend mp_testservice;
\ No newline at end of file
+%mend mp_testservice;
diff --git a/build.py b/build.py
index c4ab568..5767276 100755
--- a/build.py
+++ b/build.py
@@ -102,7 +102,7 @@ options noquotelenmax;
"""
f = open('all.sas', "w") # r / r+ / rb / rb+ / w / wb
f.write(header)
-folders = ['base', 'ddl', 'meta', 'metax', 'server', 'viya', 'lua', 'fcmp']
+folders = ['base', 'ddl', 'meta', 'metax', 'server', 'viya', 'lua', 'fcmp', 'xplatform']
for folder in folders:
filenames = [fn for fn in Path(
'./' + folder).iterdir() if fn.match("*.sas")]
diff --git a/main.dox b/main.dox
index 33459d7..1d4a2cb 100644
--- a/main.dox
+++ b/main.dox
@@ -103,4 +103,15 @@
* No X command
* Prefixes: _mddl_
- */
\ No newline at end of file
+ */
+
+/*! \dir xplatform
+ * \brief Cross Platform, works on all SAS servers (Viya, EBI, SASjs)
+ * \details Useful when you need to run a single piece of code against Viya,
+ SAS 9 with metadata, or SASjs on Base SAS.
+
+ * OS independent
+ * No X command
+ * Prefixes: _mx_
+
+ */
diff --git a/tests/crossplatform/mcf_getfmttype.test.sas b/tests/base/mcf_getfmttype.test.sas
similarity index 100%
rename from tests/crossplatform/mcf_getfmttype.test.sas
rename to tests/base/mcf_getfmttype.test.sas
diff --git a/tests/crossplatform/mcf_init.test.sas b/tests/base/mcf_init.test.sas
similarity index 100%
rename from tests/crossplatform/mcf_init.test.sas
rename to tests/base/mcf_init.test.sas
diff --git a/tests/crossplatform/mcf_length.test.sas b/tests/base/mcf_length.test.sas
similarity index 100%
rename from tests/crossplatform/mcf_length.test.sas
rename to tests/base/mcf_length.test.sas
diff --git a/tests/crossplatform/mcf_string2file.test.sas b/tests/base/mcf_string2file.test.sas
similarity index 100%
rename from tests/crossplatform/mcf_string2file.test.sas
rename to tests/base/mcf_string2file.test.sas
diff --git a/tests/crossplatform/mf_dedup.test.sas b/tests/base/mf_dedup.test.sas
similarity index 100%
rename from tests/crossplatform/mf_dedup.test.sas
rename to tests/base/mf_dedup.test.sas
diff --git a/tests/crossplatform/mf_deletefile.test.sas b/tests/base/mf_deletefile.test.sas
similarity index 100%
rename from tests/crossplatform/mf_deletefile.test.sas
rename to tests/base/mf_deletefile.test.sas
diff --git a/tests/crossplatform/mf_existds.test.sas b/tests/base/mf_existds.test.sas
similarity index 100%
rename from tests/crossplatform/mf_existds.test.sas
rename to tests/base/mf_existds.test.sas
diff --git a/tests/crossplatform/mf_existfileref.test.sas b/tests/base/mf_existfileref.test.sas
similarity index 100%
rename from tests/crossplatform/mf_existfileref.test.sas
rename to tests/base/mf_existfileref.test.sas
diff --git a/tests/crossplatform/mf_existfunction.test.sas b/tests/base/mf_existfunction.test.sas
similarity index 100%
rename from tests/crossplatform/mf_existfunction.test.sas
rename to tests/base/mf_existfunction.test.sas
diff --git a/tests/crossplatform/mf_existvar.test.sas b/tests/base/mf_existvar.test.sas
similarity index 100%
rename from tests/crossplatform/mf_existvar.test.sas
rename to tests/base/mf_existvar.test.sas
diff --git a/tests/crossplatform/mf_fmtdttm.test.sas b/tests/base/mf_fmtdttm.test.sas
similarity index 100%
rename from tests/crossplatform/mf_fmtdttm.test.sas
rename to tests/base/mf_fmtdttm.test.sas
diff --git a/tests/crossplatform/mf_getapploc.test.sas b/tests/base/mf_getapploc.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getapploc.test.sas
rename to tests/base/mf_getapploc.test.sas
diff --git a/tests/crossplatform/mf_getfilesize.test.sas b/tests/base/mf_getfilesize.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getfilesize.test.sas
rename to tests/base/mf_getfilesize.test.sas
diff --git a/tests/crossplatform/mf_getfmtlist.test.sas b/tests/base/mf_getfmtlist.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getfmtlist.test.sas
rename to tests/base/mf_getfmtlist.test.sas
diff --git a/tests/crossplatform/mf_getfmtname.test.sas b/tests/base/mf_getfmtname.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getfmtname.test.sas
rename to tests/base/mf_getfmtname.test.sas
diff --git a/tests/crossplatform/mf_getuniquefileref.test.sas b/tests/base/mf_getuniquefileref.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getuniquefileref.test.sas
rename to tests/base/mf_getuniquefileref.test.sas
diff --git a/tests/crossplatform/mf_getuniquelibref.test.sas b/tests/base/mf_getuniquelibref.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getuniquelibref.test.sas
rename to tests/base/mf_getuniquelibref.test.sas
diff --git a/tests/crossplatform/mf_getvarcount.test.sas b/tests/base/mf_getvarcount.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getvarcount.test.sas
rename to tests/base/mf_getvarcount.test.sas
diff --git a/tests/crossplatform/mf_getvarlist.test.sas b/tests/base/mf_getvarlist.test.sas
similarity index 100%
rename from tests/crossplatform/mf_getvarlist.test.sas
rename to tests/base/mf_getvarlist.test.sas
diff --git a/tests/crossplatform/mf_isint.test.sas b/tests/base/mf_isint.test.sas
similarity index 100%
rename from tests/crossplatform/mf_isint.test.sas
rename to tests/base/mf_isint.test.sas
diff --git a/tests/crossplatform/mf_islibds.test.sas b/tests/base/mf_islibds.test.sas
similarity index 100%
rename from tests/crossplatform/mf_islibds.test.sas
rename to tests/base/mf_islibds.test.sas
diff --git a/tests/crossplatform/mf_verifymacvars.test.sas b/tests/base/mf_verifymacvars.test.sas
similarity index 100%
rename from tests/crossplatform/mf_verifymacvars.test.sas
rename to tests/base/mf_verifymacvars.test.sas
diff --git a/tests/crossplatform/mf_wordsinstr1andstr2.test.sas b/tests/base/mf_wordsinstr1andstr2.test.sas
similarity index 100%
rename from tests/crossplatform/mf_wordsinstr1andstr2.test.sas
rename to tests/base/mf_wordsinstr1andstr2.test.sas
diff --git a/tests/crossplatform/mf_wordsinstr1butnotstr2.test.sas b/tests/base/mf_wordsinstr1butnotstr2.test.sas
similarity index 100%
rename from tests/crossplatform/mf_wordsinstr1butnotstr2.test.sas
rename to tests/base/mf_wordsinstr1butnotstr2.test.sas
diff --git a/tests/crossplatform/mf_writefile.test.sas b/tests/base/mf_writefile.test.sas
similarity index 100%
rename from tests/crossplatform/mf_writefile.test.sas
rename to tests/base/mf_writefile.test.sas
diff --git a/tests/crossplatform/mp_abort.test.nofix.sas b/tests/base/mp_abort.test.nofix.sas
similarity index 100%
rename from tests/crossplatform/mp_abort.test.nofix.sas
rename to tests/base/mp_abort.test.nofix.sas
diff --git a/tests/crossplatform/mp_appendfile.test.sas b/tests/base/mp_appendfile.test.sas
similarity index 100%
rename from tests/crossplatform/mp_appendfile.test.sas
rename to tests/base/mp_appendfile.test.sas
diff --git a/tests/crossplatform/mp_applyformats.test.sas b/tests/base/mp_applyformats.test.sas
similarity index 100%
rename from tests/crossplatform/mp_applyformats.test.sas
rename to tests/base/mp_applyformats.test.sas
diff --git a/tests/crossplatform/mp_assert.test.sas b/tests/base/mp_assert.test.sas
similarity index 100%
rename from tests/crossplatform/mp_assert.test.sas
rename to tests/base/mp_assert.test.sas
diff --git a/tests/crossplatform/mp_assertcolvals.test.sas b/tests/base/mp_assertcolvals.test.sas
similarity index 100%
rename from tests/crossplatform/mp_assertcolvals.test.sas
rename to tests/base/mp_assertcolvals.test.sas
diff --git a/tests/crossplatform/mp_assertdsobs.test.sas b/tests/base/mp_assertdsobs.test.sas
similarity index 100%
rename from tests/crossplatform/mp_assertdsobs.test.sas
rename to tests/base/mp_assertdsobs.test.sas
diff --git a/tests/crossplatform/mp_assertscope.test.sas b/tests/base/mp_assertscope.test.sas
similarity index 100%
rename from tests/crossplatform/mp_assertscope.test.sas
rename to tests/base/mp_assertscope.test.sas
diff --git a/tests/crossplatform/mp_base64copy.test.sas b/tests/base/mp_base64copy.test.sas
similarity index 100%
rename from tests/crossplatform/mp_base64copy.test.sas
rename to tests/base/mp_base64copy.test.sas
diff --git a/tests/crossplatform/mp_binarycopy.test.sas b/tests/base/mp_binarycopy.test.sas
similarity index 100%
rename from tests/crossplatform/mp_binarycopy.test.sas
rename to tests/base/mp_binarycopy.test.sas
diff --git a/tests/crossplatform/mp_chop.test.sas b/tests/base/mp_chop.test.sas
similarity index 100%
rename from tests/crossplatform/mp_chop.test.sas
rename to tests/base/mp_chop.test.sas
diff --git a/tests/crossplatform/mp_cntlout.test.sas b/tests/base/mp_cntlout.test.sas
similarity index 100%
rename from tests/crossplatform/mp_cntlout.test.sas
rename to tests/base/mp_cntlout.test.sas
diff --git a/tests/crossplatform/mp_copyfolder.test.sas b/tests/base/mp_copyfolder.test.sas
similarity index 100%
rename from tests/crossplatform/mp_copyfolder.test.sas
rename to tests/base/mp_copyfolder.test.sas
diff --git a/tests/crossplatform/mp_coretable.test.sas b/tests/base/mp_coretable.test.sas
similarity index 100%
rename from tests/crossplatform/mp_coretable.test.sas
rename to tests/base/mp_coretable.test.sas
diff --git a/tests/crossplatform/mp_createwebservice.test.sas b/tests/base/mp_createwebservice.test.sas
similarity index 100%
rename from tests/crossplatform/mp_createwebservice.test.sas
rename to tests/base/mp_createwebservice.test.sas
diff --git a/tests/crossplatform/mp_deletefolder.test.sas b/tests/base/mp_deletefolder.test.sas
similarity index 100%
rename from tests/crossplatform/mp_deletefolder.test.sas
rename to tests/base/mp_deletefolder.test.sas
diff --git a/tests/crossplatform/mp_dirlist.test.sas b/tests/base/mp_dirlist.test.sas
similarity index 100%
rename from tests/crossplatform/mp_dirlist.test.sas
rename to tests/base/mp_dirlist.test.sas
diff --git a/tests/crossplatform/mp_ds2cards.test.sas b/tests/base/mp_ds2cards.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2cards.test.sas
rename to tests/base/mp_ds2cards.test.sas
diff --git a/tests/crossplatform/mp_ds2csv.test.sas b/tests/base/mp_ds2csv.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2csv.test.sas
rename to tests/base/mp_ds2csv.test.sas
diff --git a/tests/crossplatform/mp_ds2fmtds.test.sas b/tests/base/mp_ds2fmtds.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2fmtds.test.sas
rename to tests/base/mp_ds2fmtds.test.sas
diff --git a/tests/crossplatform/mp_ds2inserts.test.sas b/tests/base/mp_ds2inserts.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2inserts.test.sas
rename to tests/base/mp_ds2inserts.test.sas
diff --git a/tests/crossplatform/mp_ds2md.test.sas b/tests/base/mp_ds2md.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2md.test.sas
rename to tests/base/mp_ds2md.test.sas
diff --git a/tests/crossplatform/mp_ds2squeeze.test.sas b/tests/base/mp_ds2squeeze.test.sas
similarity index 100%
rename from tests/crossplatform/mp_ds2squeeze.test.sas
rename to tests/base/mp_ds2squeeze.test.sas
diff --git a/tests/crossplatform/mp_filtercheck.test.sas b/tests/base/mp_filtercheck.test.sas
similarity index 100%
rename from tests/crossplatform/mp_filtercheck.test.sas
rename to tests/base/mp_filtercheck.test.sas
diff --git a/tests/crossplatform/mp_filtergenerate.test.sas b/tests/base/mp_filtergenerate.test.sas
similarity index 100%
rename from tests/crossplatform/mp_filtergenerate.test.sas
rename to tests/base/mp_filtergenerate.test.sas
diff --git a/tests/crossplatform/mp_filterstore.test.1.sas b/tests/base/mp_filterstore.test.1.sas
similarity index 100%
rename from tests/crossplatform/mp_filterstore.test.1.sas
rename to tests/base/mp_filterstore.test.1.sas
diff --git a/tests/crossplatform/mp_filterstore.test.2.sas b/tests/base/mp_filterstore.test.2.sas
similarity index 100%
rename from tests/crossplatform/mp_filterstore.test.2.sas
rename to tests/base/mp_filterstore.test.2.sas
diff --git a/tests/crossplatform/mp_filtervalidate.test.sas b/tests/base/mp_filtervalidate.test.sas
similarity index 100%
rename from tests/crossplatform/mp_filtervalidate.test.sas
rename to tests/base/mp_filtervalidate.test.sas
diff --git a/tests/crossplatform/mp_getcols.test.sas b/tests/base/mp_getcols.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getcols.test.sas
rename to tests/base/mp_getcols.test.sas
diff --git a/tests/crossplatform/mp_getconstraints.test.sas b/tests/base/mp_getconstraints.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getconstraints.test.sas
rename to tests/base/mp_getconstraints.test.sas
diff --git a/tests/crossplatform/mp_getddl.test.sas b/tests/base/mp_getddl.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getddl.test.sas
rename to tests/base/mp_getddl.test.sas
diff --git a/tests/crossplatform/mp_getformats.test.sas b/tests/base/mp_getformats.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getformats.test.sas
rename to tests/base/mp_getformats.test.sas
diff --git a/tests/crossplatform/mp_getmaxvarlengths.test.sas b/tests/base/mp_getmaxvarlengths.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getmaxvarlengths.test.sas
rename to tests/base/mp_getmaxvarlengths.test.sas
diff --git a/tests/crossplatform/mp_getpk.test.sas b/tests/base/mp_getpk.test.sas
similarity index 100%
rename from tests/crossplatform/mp_getpk.test.sas
rename to tests/base/mp_getpk.test.sas
diff --git a/tests/crossplatform/mp_gsubfile.test.sas b/tests/base/mp_gsubfile.test.sas
similarity index 100%
rename from tests/crossplatform/mp_gsubfile.test.sas
rename to tests/base/mp_gsubfile.test.sas
diff --git a/tests/crossplatform/mp_hashdataset.test.sas b/tests/base/mp_hashdataset.test.sas
similarity index 100%
rename from tests/crossplatform/mp_hashdataset.test.sas
rename to tests/base/mp_hashdataset.test.sas
diff --git a/tests/crossplatform/mp_init.test.sas b/tests/base/mp_init.test.sas
similarity index 100%
rename from tests/crossplatform/mp_init.test.sas
rename to tests/base/mp_init.test.sas
diff --git a/tests/crossplatform/mp_jsonout.test.1.sas b/tests/base/mp_jsonout.test.1.sas
similarity index 100%
rename from tests/crossplatform/mp_jsonout.test.1.sas
rename to tests/base/mp_jsonout.test.1.sas
diff --git a/tests/crossplatform/mp_jsonout.test.2.sas b/tests/base/mp_jsonout.test.2.sas
similarity index 100%
rename from tests/crossplatform/mp_jsonout.test.2.sas
rename to tests/base/mp_jsonout.test.2.sas
diff --git a/tests/crossplatform/mp_jsonout.test.3.sas b/tests/base/mp_jsonout.test.3.sas
similarity index 100%
rename from tests/crossplatform/mp_jsonout.test.3.sas
rename to tests/base/mp_jsonout.test.3.sas
diff --git a/tests/crossplatform/mp_lib2inserts.test.sas b/tests/base/mp_lib2inserts.test.sas
similarity index 100%
rename from tests/crossplatform/mp_lib2inserts.test.sas
rename to tests/base/mp_lib2inserts.test.sas
diff --git a/tests/crossplatform/mp_loadformat.test.sas b/tests/base/mp_loadformat.test.sas
similarity index 100%
rename from tests/crossplatform/mp_loadformat.test.sas
rename to tests/base/mp_loadformat.test.sas
diff --git a/tests/crossplatform/mp_lockanytable.test.sas b/tests/base/mp_lockanytable.test.sas
similarity index 100%
rename from tests/crossplatform/mp_lockanytable.test.sas
rename to tests/base/mp_lockanytable.test.sas
diff --git a/tests/crossplatform/mp_lockfilecheck.test.sas b/tests/base/mp_lockfilecheck.test.sas
similarity index 100%
rename from tests/crossplatform/mp_lockfilecheck.test.sas
rename to tests/base/mp_lockfilecheck.test.sas
diff --git a/tests/crossplatform/mp_makedata.test.sas b/tests/base/mp_makedata.test.sas
similarity index 100%
rename from tests/crossplatform/mp_makedata.test.sas
rename to tests/base/mp_makedata.test.sas
diff --git a/tests/crossplatform/mp_md5.test.sas b/tests/base/mp_md5.test.sas
similarity index 100%
rename from tests/crossplatform/mp_md5.test.sas
rename to tests/base/mp_md5.test.sas
diff --git a/tests/crossplatform/mp_replace.test.sas b/tests/base/mp_replace.test.sas
similarity index 100%
rename from tests/crossplatform/mp_replace.test.sas
rename to tests/base/mp_replace.test.sas
diff --git a/tests/crossplatform/mp_reseterror.test.sas b/tests/base/mp_reseterror.test.sas
similarity index 100%
rename from tests/crossplatform/mp_reseterror.test.sas
rename to tests/base/mp_reseterror.test.sas
diff --git a/tests/crossplatform/mp_resetoption.test.sas b/tests/base/mp_resetoption.test.sas
similarity index 100%
rename from tests/crossplatform/mp_resetoption.test.sas
rename to tests/base/mp_resetoption.test.sas
diff --git a/tests/crossplatform/mp_retainedkey.test.sas b/tests/base/mp_retainedkey.test.sas
similarity index 100%
rename from tests/crossplatform/mp_retainedkey.test.sas
rename to tests/base/mp_retainedkey.test.sas
diff --git a/tests/crossplatform/mp_searchcols.test.sas b/tests/base/mp_searchcols.test.sas
similarity index 100%
rename from tests/crossplatform/mp_searchcols.test.sas
rename to tests/base/mp_searchcols.test.sas
diff --git a/tests/crossplatform/mp_searchdata.test.sas b/tests/base/mp_searchdata.test.sas
similarity index 100%
rename from tests/crossplatform/mp_searchdata.test.sas
rename to tests/base/mp_searchdata.test.sas
diff --git a/tests/crossplatform/mp_sortinplace.test.sas b/tests/base/mp_sortinplace.test.sas
similarity index 100%
rename from tests/crossplatform/mp_sortinplace.test.sas
rename to tests/base/mp_sortinplace.test.sas
diff --git a/tests/crossplatform/mp_stackdiffs.test.sas b/tests/base/mp_stackdiffs.test.sas
similarity index 100%
rename from tests/crossplatform/mp_stackdiffs.test.sas
rename to tests/base/mp_stackdiffs.test.sas
diff --git a/tests/crossplatform/mp_storediffs.test.sas b/tests/base/mp_storediffs.test.sas
similarity index 100%
rename from tests/crossplatform/mp_storediffs.test.sas
rename to tests/base/mp_storediffs.test.sas
diff --git a/tests/crossplatform/mp_streamfile.test.sas b/tests/base/mp_streamfile.test.sas
similarity index 100%
rename from tests/crossplatform/mp_streamfile.test.sas
rename to tests/base/mp_streamfile.test.sas
diff --git a/tests/crossplatform/mp_validatecol.test.sas b/tests/base/mp_validatecol.test.sas
similarity index 100%
rename from tests/crossplatform/mp_validatecol.test.sas
rename to tests/base/mp_validatecol.test.sas
diff --git a/tests/crossplatform/mp_webin.test.sas b/tests/base/mp_webin.test.sas
similarity index 100%
rename from tests/crossplatform/mp_webin.test.sas
rename to tests/base/mp_webin.test.sas
diff --git a/tests/crossplatform/mp_zip.test.sas b/tests/base/mp_zip.test.sas
similarity index 100%
rename from tests/crossplatform/mp_zip.test.sas
rename to tests/base/mp_zip.test.sas
diff --git a/tests/xplatform/mx_getcode.test.sas b/tests/xplatform/mx_getcode.test.sas
new file mode 100644
index 0000000..7e4cae2
--- /dev/null
+++ b/tests/xplatform/mx_getcode.test.sas
@@ -0,0 +1,38 @@
+/**
+ @file
+ @brief Testing mx_getcode.test.sas macro
+
+ Be sure to run %let mcTestAppLoc=/Public/temp/macrocore; when
+ running in Studio
+
+ SAS Macros
+ @li mf_uid.sas
+ @li mp_assert.sas
+ @li mx_createwebservice.sas
+ @li mx_getcode.sas
+ @li mx_testservice.sas
+
+**/
+
+/* first create a service */
+
+%let item=%mf_uid();;
+
+%global test1;
+%let test1=FAIL;
+
+filename ft15f001 temp;
+parmcards4;
+ %let test1=SUCCESS;
+;;;;
+%mx_createwebservice(path=&mcTestAppLoc/temp,name=&item)
+
+%mx_getcode(&mcTestAppLoc/temp/&item,testref1)
+
+%inc testref1/lrecl=1000;
+
+%mp_assert(
+ iftrue=(&test1=SUCCESS),
+ desc=code was successfully fetched,
+ outds=work.test_results
+)
diff --git a/tests/crossplatform/mp_testservice.test.sas b/tests/xplatform/mx_testservice.test.sas
similarity index 89%
rename from tests/crossplatform/mp_testservice.test.sas
rename to tests/xplatform/mx_testservice.test.sas
index d52cefc..c2b2db4 100644
--- a/tests/crossplatform/mp_testservice.test.sas
+++ b/tests/xplatform/mx_testservice.test.sas
@@ -1,13 +1,13 @@
/**
@file
- @brief Testing mp_testservice.sas macro
+ @brief Testing mx_testservice.sas macro
Be sure to run %let mcTestAppLoc=/Public/temp/macrocore; when
runnin in Studio
SAS Macros
@li mp_createwebservice.sas
- @li mp_testservice.sas
+ @li mx_testservice.sas
@li mp_assert.sas
**/
@@ -29,7 +29,7 @@ parmcards4;
%mend x; %x()
%webout(CLOSE)
;;;;
-%mp_createwebservice(path=&mcTestAppLoc/services,name=sendObj)
+%mx_createwebservice(path=&mcTestAppLoc/services,name=sendObj)
%mp_assert(
iftrue=(&syscc=0),
@@ -48,7 +48,7 @@ data work.somedata1 work.somedata2;
output;
run;
-%mp_testservice(&mcTestAppLoc/services/sendObj,
+%mx_testservice(&mcTestAppLoc/services/sendObj,
inputdatasets=work.somedata1 work.somedata2,
debug=log,
mdebug=1,
diff --git a/xplatform/mx_createwebservice.sas b/xplatform/mx_createwebservice.sas
new file mode 100644
index 0000000..a11de55
--- /dev/null
+++ b/xplatform/mx_createwebservice.sas
@@ -0,0 +1,96 @@
+/**
+ @file mx_createwebservice.sas
+ @brief Create a web service in SAS 9, Viya or SASjs
+ @details Creates a SASJS ready Stored Process in SAS 9, a Job Execution
+ Service in SAS Viya, and a Stored Program on SASjs Server
+
+Usage:
+
+ %* compile macros ;
+ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
+ %inc mc;
+
+ %* write some code;
+ filename ft15f001 temp;
+ parmcards4;
+ %* fetch any data from frontend ;
+ %webout(FETCH)
+ data example1 example2;
+ set sashelp.class;
+ run;
+ %* send data back;
+ %webout(OPEN)
+ %webout(ARR,example1) * Array format, fast, suitable for large tables ;
+ %webout(OBJ,example2) * Object format, easier to work with ;
+ %webout(CLOSE)
+ ;;;;
+ %mp_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
+
+ SAS Macros
+ @li mf_getplatform.sas
+ @li mm_createwebservice.sas
+ @li ms_createwebservice.sas
+ @li mv_createwebservice.sas
+
+ @param [in,out] path= The full folder path where the service will be created
+ @param [in,out] name= Service name. Avoid spaces.
+ @param [in] desc= The description of the service (optional)
+ @param [in] precode= Space separated list of filerefs, pointing to the code
+ that needs to be attached to the beginning of the service (optional)
+ @param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
+ be added
+ @param [in] replace= (YES) Select YES to replace any existing service in that
+ location
+ @param [in] mDebug= (0) set to 1 to show debug messages in the log
+
+ @version 9.2
+ @author Allan Bowe
+
+**/
+
+%macro mx_createwebservice(path=HOME
+ ,name=initService
+ ,precode=
+ ,code=ft15f001
+ ,desc=This service was created by the mp_createwebservice macro
+ ,replace=YES
+ ,mdebug=0
+)/*/STORE SOURCE*/;
+
+%if &syscc ge 4 %then %do;
+ %put syscc=&syscc - &sysmacroname will not execute in this state;
+ %return;
+%end;
+
+%local platform; %let platform=%mf_getplatform();
+%if &platform=SASVIYA %then %do;
+ %if "&path"="HOME" %then %let path=/Users/&sysuserid/My Folder;
+ %mv_createwebservice(path=&path
+ ,name=&name
+ ,code=&code
+ ,precode=&precode
+ ,desc=&desc
+ ,replace=&replace
+ )
+%end;
+%else %if &platform=SASJS %then %do;
+ %if "&path"="HOME" %then %let path=/Users/&_sasjs_username/My Folder;
+ %ms_createwebservice(path=&path
+ ,name=&name
+ ,code=&code
+ ,precode=&precode
+ ,mdebug=&mdebug
+ )
+%end;
+%else %do;
+ %if "&path"="HOME" %then %let path=/User Folders/&_METAPERSON/My Folder;
+ %mm_createwebservice(path=&path
+ ,name=&name
+ ,code=&code
+ ,precode=&precode
+ ,desc=&desc
+ ,replace=&replace
+ )
+%end;
+
+%mend mx_createwebservice;
diff --git a/xplatform/mx_getcode.sas b/xplatform/mx_getcode.sas
new file mode 100644
index 0000000..ee689a6
--- /dev/null
+++ b/xplatform/mx_getcode.sas
@@ -0,0 +1,57 @@
+/**
+ @file
+ @brief Fetches code from Viya Job, SAS 9 STP, or SASjs Server STP
+ @details When building applications that run on multiple flavours of SAS, it
+ is convenient to use a single macro (like this one) to fetch the source
+ code from a Viya Job, SAS 9 Stored Process, or SASjs Stored Program.
+
+ The alternative would be to compile a generic macro in target-specific
+ folders (SASVIYA, SAS9 and SASJS). This avoids compiling unnecessary macros
+ at the expense of a more complex sasjsconfig.json setup.
+
+
+ @param [in] loc The full path to the Viya Job, SAS 9 Stored Process or SASjs
+ Stored Program in Drive or Metadata, WITHOUT the .sas extension (SASjs only)
+ @param [out] outref= (0) The fileref to create, which will contain the source
+ code.
+
+ SAS Macros
+ @li mf_getplatform.sas
+ @li mf_getuniquename.sas
+ @li mm_getstpcode.sas
+ @li ms_getfile.sas
+
+ @author Allan Bowe
+
+**/
+
+%macro mx_getcode(loc,outref=0
+)/*/STORE SOURCE*/;
+
+%local platform name shortloc;
+%let platform=%mf_getplatform();
+
+%if &platform=SASJS %then %do;
+ %ms_getfile(&loc..sas, outref=&outref)
+%end;
+%else %if &platform=SAS9 %then %do;
+ %mm_getstpcode(tree=&loc,outloc=&outref)
+%end;
+%else %if &platform=SASVIYA %then %do;
+ /* extract name & path from &loc */
+ data _null_;
+ loc=symget('loc');
+ name=scan(loc,-1,'/');
+ shortloc=substr(loc,1,length(loc)-length(name)-1);
+ call symputx('name',name,'l');
+ call symputx('shortloc',shortloc,'l');
+ run;
+ %mv_getjobcode(
+ path=&shortloc,
+ name=&name,
+ outref=&outref
+ )
+%end;
+%else %put &sysmacroname: &platform is unsupported!!!;
+
+%mend mx_getcode;
diff --git a/xplatform/mx_testservice.sas b/xplatform/mx_testservice.sas
new file mode 100644
index 0000000..6a089d3
--- /dev/null
+++ b/xplatform/mx_testservice.sas
@@ -0,0 +1,299 @@
+/**
+ @file
+ @brief Will execute a SASjs web service on SAS 9, Viya or SASjs Server
+ @details Prepares the input files and retrieves the resulting datasets from
+ the response JSON.
+
+ Note - the _webout fileref should NOT be assigned prior to running this macro.
+
+ @param [in] program The _PROGRAM endpoint to test
+ @param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
+ follows:
+ inputfiles=inref:filename inref2:filename2
+ @param [in] inputdatasets= (0) All datasets in this space seperated list are
+ converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to
+ the list of `inputfiles` for ingestion. The dataset will be sent with the
+ same name (no need for a colon modifier).
+ @param [in] inputparams=(0) A dataset containing name/value pairs in the
+ following format:
+ |name:$32|value:$1000|
+ |---|---|
+ |stpmacname|some value|
+ |mustbevalidname|can be anything, oops, %abort!!|
+
+ @param [in] debug= (log) Provide the _debug value
+ @param [in] mdebug= (0) Set to 1 to provide macro debugging
+ @param [in] viyaresult= (WEBOUT_JSON) The Viya result type to return. For
+ more info, see mv_getjobresult.sas
+ @param [in] viyacontext= (SAS Job Execution compute context) The Viya compute
+ context on which to run the service
+ @param [out] outlib= (0) Output libref to contain the final tables. Set to
+ 0 if the service output is not in JSON format.
+ @param [out] outref= (0) Output fileref to create, to contain the full _webout
+ response.
+
+ SAS Macros
+ @li mf_getplatform.sas
+ @li mf_getuniquefileref.sas
+ @li mf_getuniquename.sas
+ @li mp_abort.sas
+ @li mp_binarycopy.sas
+ @li mp_chop.sas
+ @li mp_ds2csv.sas
+ @li ms_testservice.sas
+ @li mv_getjobresult.sas
+ @li mv_jobflow.sas
+
+ Related Programs
+ @li mx_testservice.test.sas
+
+ @version 9.4
+ @author Allan Bowe
+
+**/
+
+%macro mx_testservice(program,
+ inputfiles=0,
+ inputdatasets=0,
+ inputparams=0,
+ debug=log,
+ mdebug=0,
+ outlib=0,
+ outref=0,
+ viyaresult=WEBOUT_JSON,
+ viyacontext=SAS Job Execution compute context
+);
+%local dbg pcnt fref1 fref2 webref webrefpath i webcount var platform;
+%if &mdebug=1 %then %do;
+ %put &sysmacroname entry vars:;
+ %put _local_;
+%end;
+%else %let dbg=*;
+
+/* sanitise inputparams */
+%let pcnt=0;
+%if &inputparams ne 0 %then %do;
+ data _null_;
+ set &inputparams;
+ if not nvalid(name,'v7') then putlog (_all_)(=);
+ else if name in (
+ 'program','inputfiles','inputparams','debug','outlib','outref'
+ ) then putlog (_all_)(=);
+ else do;
+ x+1;
+ call symputx(name,quote(cats(value)),'l');
+ call symputx(cats('pval',x),name,'l');
+ call symputx('pcnt',x,'l');
+ end;
+ run;
+ %mp_abort(iftrue= (%mf_nobs(&inputparams) ne &pcnt)
+ ,mac=&sysmacroname
+ ,msg=%str(Invalid values in &inputparams)
+ )
+%end;
+
+/* convert inputdatasets to filerefs */
+%if "&inputdatasets" ne "0" %then %do;
+ %if %quote(&inputfiles)=0 %then %let inputfiles=;
+ %do i=1 %to %sysfunc(countw(&inputdatasets,%str( )));
+ %let var=%scan(&inputdatasets,&i,%str( ));
+ %local dsref&i;
+ %let dsref&i=%mf_getuniquefileref();
+ %mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS)
+ %let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.);
+ %end;
+%end;
+
+%let platform=%mf_getplatform();
+%let fref1=%mf_getuniquefileref();
+%let fref2=%mf_getuniquefileref();
+%let webref=%mf_getuniquefileref();
+%let webrefpath=%sysfunc(pathname(work))/%mf_getuniquename();
+/* mp_chop requires a physical path as input */
+filename &webref "&webrefpath";
+
+%if &platform=SASMETA %then %do;
+
+ /* parse the input files */
+ %if %quote(&inputfiles) ne 0 %then %do;
+ %let webcount=%sysfunc(countw(&inputfiles));
+ %put &=webcount;
+ %do i=1 %to &webcount;
+ %let var=%scan(&inputfiles,&i,%str( ));
+ %local webfref&i webname&i;
+ %let webref&i=%scan(&var,1,%str(:));
+ %let webname&i=%scan(&var,2,%str(:));
+ %put webref&i=&&webref&i;
+ %put webname&i=&&webname&i;
+ %end;
+ %end;
+ %else %let webcount=0;
+
+ proc stp program="&program";
+ inputparam _program="&program"
+ %do i=1 %to &webcount;
+ %if &webcount=1 %then %do;
+ _webin_fileref="&&webref&i"
+ _webin_name="&&webname&i"
+ %end;
+ %else %do;
+ _webin_fileref&i="&&webref&i"
+ _webin_name&i="&&webname&i"
+ %end;
+ %end;
+ _webin_file_count="&webcount"
+ _debug="&debug"
+ %do i=1 %to &pcnt;
+ /* resolve name only, proc stp fetches value */
+ &&pval&i=&&&&&&pval&i
+ %end;
+ ;
+ %do i=1 %to &webcount;
+ inputfile &&webref&i;
+ %end;
+ outputfile _webout=&webref;
+ run;
+
+ data _null_;
+ infile &webref;
+ file &fref1;
+ input;
+ length line $10000;
+ if index(_infile_,'>>weboutBEGIN<<') then do;
+ line=tranwrd(_infile_,'>>weboutBEGIN<<','');
+ put line;
+ end;
+ else if index(_infile_,'>>weboutEND<<') then do;
+ line=tranwrd(_infile_,'>>weboutEND<<','');
+ put line;
+ stop;
+ end;
+ else put _infile_;
+ run;
+ data _null_;
+ infile &fref1;
+ input;
+ put _infile_;
+ run;
+ %if &outlib ne 0 %then %do;
+ libname &outlib json (&fref1);
+ %end;
+ %if &outref ne 0 %then %do;
+ filename &outref temp;
+ %mp_binarycopy(inref=&webref,outref=&outref)
+ %end;
+
+%end;
+%else %if &platform=SASVIYA %then %do;
+
+ /* prepare inputparams */
+ %local ds1;
+ %let ds1=%mf_getuniquename();
+ %if "&inputparams" ne "0" %then %do;
+ proc transpose data=&inputparams out=&ds1;
+ id name;
+ var value;
+ run;
+ %end;
+ %else %do;
+ data &ds1;run;
+ %end;
+
+ /* parse the input files - convert to sasjs params */
+ %local webcount i var sasjs_tables;
+ %if %quote(&inputfiles) ne 0 %then %do;
+ %let webcount=%sysfunc(countw(&inputfiles));
+ %put &=webcount;
+ %do i=1 %to &webcount;
+ %let var=%scan(&inputfiles,&i,%str( ));
+ %local webfref&i webname&i sasjs&i.data;
+ %let webref&i=%scan(&var,1,%str(:));
+ %let webname&i=%scan(&var,2,%str(:));
+ %put webref&i=&&webref&i;
+ %put webname&i=&&webname&i;
+
+ %let sasjs_tables=&sasjs_tables &&webname&i;
+ data _null_;
+ infile &&webref&i lrecl=32767;
+ input;
+ if _n_=1 then call symputx("sasjs&i.data",_infile_);
+ else call symputx(
+ "sasjs&i.data",cats(symget("sasjs&i.data"),'0D0A'x,_infile_)
+ );
+ putlog "&sysmacroname infile: " _infile_;
+ run;
+ data &ds1;
+ set &ds1;
+ length sasjs&i.data $32767 sasjs_tables $1000;
+ sasjs&i.data=symget("sasjs&i.data");
+ sasjs_tables=symget("sasjs_tables");
+ run;
+ %end;
+ %end;
+ %else %let webcount=0;
+
+ data &ds1;
+ retain _program "&program";
+ retain _contextname "&viyacontext";
+ set &ds1;
+ putlog "&sysmacroname inputparams:";
+ putlog (_all_)(=);
+ run;
+
+ %mv_jobflow(inds=&ds1
+ ,maxconcurrency=1
+ ,outds=work.results
+ ,outref=&fref1
+ ,mdebug=&mdebug
+ )
+ /* show the log */
+ data _null_;
+ infile &fref1;
+ input;
+ putlog _infile_;
+ run;
+ /* get the uri to fetch results */
+ data _null_;
+ set work.results;
+ call symputx('uri',uri);
+ putlog "&sysmacroname: fetching results for " uri;
+ run;
+ /* fetch results from webout.json */
+ %mv_getjobresult(uri=&uri,
+ result=&viyaresult,
+ outref=&outref,
+ outlib=&outlib,
+ mdebug=&mdebug
+ )
+
+%end;
+%else %if &platform=SASJS %then %do;
+
+ %ms_testservice(&program
+ ,inputfiles=&inputfiles
+ ,inputdatasets=&inputdatasets
+ ,inputparams=&inputparams
+ ,debug=&debug
+ ,mdebug=&mdebug
+ ,outlib=&outlib
+ ,outref=&outref
+ )
+
+%end;
+%else %do;
+ %put %str(ERR)OR: Unrecognised platform: &platform;
+%end;
+
+%if &mdebug=0 %then %do;
+ filename &fref1 clear;
+ %if &platform ne SASJS %then %do;
+ filename &fref2 clear;
+ filename &webref clear;
+ %end;
+%end;
+%else %do;
+ %put &sysmacroname exit vars:;
+ %put _local_;
+%end;
+
+%mend mx_testservice;