From 7a696981788daa3466ab96728e5020d979686be3 Mon Sep 17 00:00:00 2001 From: munja Date: Sun, 26 Jun 2022 16:12:49 +0100 Subject: [PATCH] fix: adding fileref options and an additional test for mp_binarycopy --- all.sas | 46 ++++++++++++++----------------- base/mp_binarycopy.sas | 21 ++++++-------- base/mp_jsonout.sas | 6 ++-- meta/mm_createwebservice.sas | 6 ++-- sasjs/sasjsconfig.json | 3 +- server/ms_createwebservice.sas | 6 ++-- tests/base/mp_binarycopy.test.sas | 39 +++++++++++++++++++++++++- viya/mv_createwebservice.sas | 6 ++-- 8 files changed, 81 insertions(+), 52 deletions(-) diff --git a/all.sas b/all.sas index 4b9e42a..f3bb790 100644 --- a/all.sas +++ b/all.sas @@ -3470,8 +3470,8 @@ run; @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: - https://stackoverflow.com/questions/13046116/using-sas-to-copy-a-text-file + Note that if you have a new enough version of SAS, and you don't need features + such as APPEND, you may be better of using the fcopy() function instead. %mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout) @@ -3511,14 +3511,9 @@ run; ,outref=____out /* override default to use own filerefs */ ,mode=CREATE )/*/STORE SOURCE*/; - %local mod outmode; - %if &mode=APPEND %then %do; - %let mod=mod; - %let outmode='a'; - %end; - %else %do; - %let outmode='o'; - %end; + %local mod; + %if &mode=APPEND %then %let mod=mod; + /* these IN and OUT filerefs can point to anything */ %if &inref = ____in %then %do; filename &inref &inloc lrecl=1048576 ; @@ -3529,8 +3524,8 @@ run; /* copy the file byte-for-byte */ data _null_; - infile &inref; - file &outref; + infile &inref lrecl=1 recfm=n; + file &outref &mod recfm=n; input sourcechar $char1. @@; format sourcechar hex2.; put sourcechar char1. @@; @@ -3542,7 +3537,8 @@ run; %if &outref=____out %then %do; filename &outref clear; %end; -%mend mp_binarycopy;/** +%mend mp_binarycopy; +/** @file @brief Splits a file of ANY SIZE by reference to a search string. @details Provide a fileref and a search string to chop off part of a file. @@ -8812,10 +8808,10 @@ options "&&name&i"n /* name literal for reserved variable names */ %end; %if &action=ARR %then "]" ; %else "}" ; ; - /* now write the long strings to _webout 1 byte at a time */ + /* now write the long strings to _webout 1 char at a time */ data _null_; - infile _sjs; - file &jref mod; + infile _sjs lrecl=1 recfm=n; + file &jref mod lrecl=1 recfm=n; input sourcechar $char1. @@; format sourcechar hex2.; put sourcechar char1. @@; @@ -15189,10 +15185,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; '; @@ -19922,10 +19918,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; '; @@ -22263,10 +22259,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; '; diff --git a/base/mp_binarycopy.sas b/base/mp_binarycopy.sas index 57377d8..b6b3d04 100755 --- a/base/mp_binarycopy.sas +++ b/base/mp_binarycopy.sas @@ -4,8 +4,8 @@ @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: - https://stackoverflow.com/questions/13046116/using-sas-to-copy-a-text-file + Note that if you have a new enough version of SAS, and you don't need features + such as APPEND, you may be better of using the fcopy() function instead. %mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout) @@ -45,14 +45,9 @@ ,outref=____out /* override default to use own filerefs */ ,mode=CREATE )/*/STORE SOURCE*/; - %local mod outmode; - %if &mode=APPEND %then %do; - %let mod=mod; - %let outmode='a'; - %end; - %else %do; - %let outmode='o'; - %end; + %local mod; + %if &mode=APPEND %then %let mod=mod; + /* these IN and OUT filerefs can point to anything */ %if &inref = ____in %then %do; filename &inref &inloc lrecl=1048576 ; @@ -63,8 +58,8 @@ /* copy the file byte-for-byte */ data _null_; - infile &inref; - file &outref; + infile &inref lrecl=1 recfm=n; + file &outref &mod recfm=n; input sourcechar $char1. @@; format sourcechar hex2.; put sourcechar char1. @@; @@ -76,4 +71,4 @@ %if &outref=____out %then %do; filename &outref clear; %end; -%mend mp_binarycopy; \ No newline at end of file +%mend mp_binarycopy; diff --git a/base/mp_jsonout.sas b/base/mp_jsonout.sas index 4caee28..924f333 100644 --- a/base/mp_jsonout.sas +++ b/base/mp_jsonout.sas @@ -234,10 +234,10 @@ "&&name&i"n /* name literal for reserved variable names */ %end; %if &action=ARR %then "]" ; %else "}" ; ; - /* now write the long strings to _webout 1 byte at a time */ + /* now write the long strings to _webout 1 char at a time */ data _null_; - infile _sjs; - file &jref mod; + infile _sjs lrecl=1 recfm=n; + file &jref mod lrecl=1 recfm=n; input sourcechar $char1. @@; format sourcechar hex2.; put sourcechar char1. @@; diff --git a/meta/mm_createwebservice.sas b/meta/mm_createwebservice.sas index d4f6220..9285e5c 100644 --- a/meta/mm_createwebservice.sas +++ b/meta/mm_createwebservice.sas @@ -268,10 +268,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; '; diff --git a/sasjs/sasjsconfig.json b/sasjs/sasjsconfig.json index d1218ca..e900f79 100644 --- a/sasjs/sasjsconfig.json +++ b/sasjs/sasjsconfig.json @@ -67,6 +67,7 @@ }, { "name": "server", + "serverUrl": "", "serverType": "SASJS", "httpsAgentOptions": { "allowInsecureRequests": false @@ -106,4 +107,4 @@ "contextName": "SAS Job Execution compute context" } ] -} \ No newline at end of file +} diff --git a/server/ms_createwebservice.sas b/server/ms_createwebservice.sas index cd7ca4d..e3d392e 100644 --- a/server/ms_createwebservice.sas +++ b/server/ms_createwebservice.sas @@ -269,10 +269,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; '; diff --git a/tests/base/mp_binarycopy.test.sas b/tests/base/mp_binarycopy.test.sas index b456c21..7ce3f37 100644 --- a/tests/base/mp_binarycopy.test.sas +++ b/tests/base/mp_binarycopy.test.sas @@ -5,6 +5,7 @@

SAS Macros

@li mp_binarycopy.sas @li mp_assert.sas + @li mp_hashdataset.sas **/ @@ -96,4 +97,40 @@ run; iftrue=("&string4"="&string4_check"), desc=Append Check (ref to file), outds=work.test_results -) \ No newline at end of file +) + +/* test 5 - ensure copy works for binary characters */ +/* do this backwards to avoid null chars in JSON preview */ +data work.test5; +do i=255 to 1 by -1; + str=byte(i); + output; +end; +run; +/* get an md5 hash of the ds */ +%mp_hashdataset(work.test5,outds=myhash) + +/* copy it */ +%mp_binarycopy(inloc="%sysfunc(pathname(work))/test5.sas7bdat", + outloc="%sysfunc(pathname(work))/test5copy.sas7bdat" +) + +/* get an md5 hash of the copied ds */ +%mp_hashdataset(work.test5copy,outds=myhash2) + +/* compare hashes */ +%let test5a=0; +%let test5b=1; +data _null_; + set myhash; + call symputx('test5a',hashkey); +run; +data _null_; + set myhash2; + call symputx('test5b',hashkey); +run; +%mp_assert( + iftrue=("&test5a"="&test5b"), + desc=Ensuring binary copy works on binary characters, + outds=work.test_results +) diff --git a/viya/mv_createwebservice.sas b/viya/mv_createwebservice.sas index 56e2929..5b3f18a 100644 --- a/viya/mv_createwebservice.sas +++ b/viya/mv_createwebservice.sas @@ -411,10 +411,10 @@ data _null_; put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' %end; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; '; - put ' /* now write the long strings to _webout 1 byte at a time */ '; + put ' /* now write the long strings to _webout 1 char at a time */ '; put ' data _null_; '; - put ' infile _sjs; '; - put ' file &jref mod; '; + put ' infile _sjs lrecl=1 recfm=n; '; + put ' file &jref mod lrecl=1 recfm=n; '; put ' input sourcechar $char1. @@; '; put ' format sourcechar hex2.; '; put ' put sourcechar char1. @@; ';