@sasjs/utils 2.49.0 → 2.49.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/fs/internal/helper.js +19 -24
  2. package/fs/internal/helper.js.map +1 -1
  3. package/macros/mf_abort.sas +27 -0
  4. package/macros/mf_dedup.sas +53 -0
  5. package/macros/mf_deletefile.sas +31 -0
  6. package/macros/mf_existds.sas +30 -0
  7. package/macros/mf_existfeature.sas +59 -0
  8. package/macros/mf_existfileref.sas +33 -0
  9. package/macros/mf_existfunction.sas +37 -0
  10. package/macros/mf_existvar.sas +39 -0
  11. package/macros/mf_existvarlist.sas +56 -0
  12. package/macros/mf_fmtdttm.sas +42 -0
  13. package/macros/mf_getapploc.sas +78 -0
  14. package/macros/mf_getattrc.sas +34 -0
  15. package/macros/mf_getattrn.sas +34 -0
  16. package/macros/mf_getengine.sas +54 -0
  17. package/macros/mf_getfilesize.sas +64 -0
  18. package/macros/mf_getfmtlist.sas +61 -0
  19. package/macros/mf_getfmtname.sas +44 -0
  20. package/macros/mf_getkeyvalue.sas +32 -0
  21. package/macros/mf_getplatform.sas +75 -0
  22. package/macros/mf_getquotedstr.sas +57 -0
  23. package/macros/mf_getschema.sas +43 -0
  24. package/macros/mf_getuniquefileref.sas +60 -0
  25. package/macros/mf_getuniquelibref.sas +57 -0
  26. package/macros/mf_getuniquename.sas +22 -0
  27. package/macros/mf_getuser.sas +44 -0
  28. package/macros/mf_getvalue.sas +36 -0
  29. package/macros/mf_getvarcount.sas +49 -0
  30. package/macros/mf_getvarformat.sas +72 -0
  31. package/macros/mf_getvarlen.sas +56 -0
  32. package/macros/mf_getvarlist.sas +74 -0
  33. package/macros/mf_getvarnum.sas +58 -0
  34. package/macros/mf_getvartype.sas +52 -0
  35. package/macros/mf_getxengine.sas +43 -0
  36. package/macros/mf_increment.sas +29 -0
  37. package/macros/mf_isblank.sas +27 -0
  38. package/macros/mf_isdir.sas +34 -0
  39. package/macros/mf_isint.sas +36 -0
  40. package/macros/mf_islibds.sas +40 -0
  41. package/macros/mf_loc.sas +29 -0
  42. package/macros/mf_mkdir.sas +67 -0
  43. package/macros/mf_mval.sas +19 -0
  44. package/macros/mf_nobs.sas +26 -0
  45. package/macros/mf_trimstr.sas +50 -0
  46. package/macros/mf_uid.sas +21 -0
  47. package/macros/mf_verifymacvars.sas +72 -0
  48. package/macros/mf_wordsinstr1andstr2.sas +53 -0
  49. package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
  50. package/macros/mf_writefile.sas +67 -0
  51. package/macros/mp_abort.sas +301 -0
  52. package/macros/mp_appendfile.sas +57 -0
  53. package/macros/mp_applyformats.sas +181 -0
  54. package/macros/mp_assert.sas +56 -0
  55. package/macros/mp_assertcols.sas +145 -0
  56. package/macros/mp_assertcolvals.sas +168 -0
  57. package/macros/mp_assertdsobs.sas +121 -0
  58. package/macros/mp_assertscope.sas +147 -0
  59. package/macros/mp_base64copy.sas +117 -0
  60. package/macros/mp_binarycopy.sas +79 -0
  61. package/macros/mp_chop.sas +194 -0
  62. package/macros/mp_cleancsv.sas +78 -0
  63. package/macros/mp_cntlout.sas +85 -0
  64. package/macros/mp_copyfolder.sas +84 -0
  65. package/macros/mp_coretable.sas +73 -0
  66. package/macros/mp_createconstraints.sas +70 -0
  67. package/macros/mp_createwebservice.sas +32 -0
  68. package/macros/mp_csv2ds.sas +140 -0
  69. package/macros/mp_deleteconstraints.sas +52 -0
  70. package/macros/mp_deletefolder.sas +70 -0
  71. package/macros/mp_dictionary.sas +52 -0
  72. package/macros/mp_dirlist.sas +262 -0
  73. package/macros/mp_distinctfmtvalues.sas +50 -0
  74. package/macros/mp_dropmembers.sas +46 -0
  75. package/macros/mp_ds2cards.sas +291 -0
  76. package/macros/mp_ds2csv.sas +212 -0
  77. package/macros/mp_ds2ddl.sas +30 -0
  78. package/macros/mp_ds2fmtds.sas +105 -0
  79. package/macros/mp_ds2inserts.sas +180 -0
  80. package/macros/mp_ds2md.sas +103 -0
  81. package/macros/mp_ds2squeeze.sas +120 -0
  82. package/macros/mp_dsmeta.sas +110 -0
  83. package/macros/mp_filtercheck.sas +251 -0
  84. package/macros/mp_filtergenerate.sas +105 -0
  85. package/macros/mp_filterstore.sas +254 -0
  86. package/macros/mp_filtervalidate.sas +105 -0
  87. package/macros/mp_getcols.sas +67 -0
  88. package/macros/mp_getconstraints.sas +115 -0
  89. package/macros/mp_getdbml.sas +335 -0
  90. package/macros/mp_getddl.sas +400 -0
  91. package/macros/mp_getformats.sas +124 -0
  92. package/macros/mp_getmaxvarlengths.sas +130 -0
  93. package/macros/mp_getpk.sas +281 -0
  94. package/macros/mp_gitadd.sas +45 -0
  95. package/macros/mp_gitreleaseinfo.sas +74 -0
  96. package/macros/mp_gitstatus.sas +67 -0
  97. package/macros/mp_gsubfile.sas +58 -0
  98. package/macros/mp_guesspk.sas +332 -0
  99. package/macros/mp_hashdataset.sas +91 -0
  100. package/macros/mp_hashdirectory.sas +164 -0
  101. package/macros/mp_include.sas +106 -0
  102. package/macros/mp_init.sas +76 -0
  103. package/macros/mp_jsonout.sas +406 -0
  104. package/macros/mp_lib2cards.sas +78 -0
  105. package/macros/mp_lib2inserts.sas +77 -0
  106. package/macros/mp_loadformat.sas +303 -0
  107. package/macros/mp_lockanytable.sas +243 -0
  108. package/macros/mp_lockfilecheck.sas +103 -0
  109. package/macros/mp_makedata.sas +107 -0
  110. package/macros/mp_md5.sas +58 -0
  111. package/macros/mp_perflog.sas +43 -0
  112. package/macros/mp_prevobs.sas +88 -0
  113. package/macros/mp_recursivejoin.sas +90 -0
  114. package/macros/mp_replace.sas +151 -0
  115. package/macros/mp_reseterror.sas +27 -0
  116. package/macros/mp_resetoption.sas +39 -0
  117. package/macros/mp_retainedkey.sas +247 -0
  118. package/macros/mp_runddl.sas +49 -0
  119. package/macros/mp_searchcols.sas +103 -0
  120. package/macros/mp_searchdata.sas +131 -0
  121. package/macros/mp_setkeyvalue.sas +55 -0
  122. package/macros/mp_sortinplace.sas +122 -0
  123. package/macros/mp_stackdiffs.sas +592 -0
  124. package/macros/mp_storediffs.sas +230 -0
  125. package/macros/mp_stprequests.sas +74 -0
  126. package/macros/mp_streamfile.sas +212 -0
  127. package/macros/mp_testjob.sas +92 -0
  128. package/macros/mp_testservice.sas +39 -0
  129. package/macros/mp_testwritespeedlibrary.sas +59 -0
  130. package/macros/mp_tree.sas +71 -0
  131. package/macros/mp_unzip.sas +90 -0
  132. package/macros/mp_updatevarlength.sas +93 -0
  133. package/macros/mp_validatecol.sas +97 -0
  134. package/macros/mp_wait4file.sas +35 -0
  135. package/macros/mp_webin.sas +59 -0
  136. package/macros/mp_zip.sas +85 -0
  137. package/package.json +5 -2
  138. package/scripts/copySASjsCore.ts +36 -0
  139. package/utils/index.d.ts +1 -2
  140. package/utils/index.js +2 -3
  141. package/utils/index.js.map +1 -1
  142. package/utils/utils.d.ts +1 -0
  143. package/utils/utils.js +7 -1
  144. package/utils/utils.js.map +1 -1
  145. package/utils/getNodeModulePath.d.ts +0 -2
  146. package/utils/getNodeModulePath.js +0 -83
  147. package/utils/getNodeModulePath.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ /**
2
+ @file
3
+ @brief Create sample data based on the structure of an empty table
4
+ @details Many SAS projects involve sensitive datasets. One way to _ensure_
5
+ the data is anonymised, is never to receive it in the first place! Often
6
+ consultants are provided with empty tables, and expected to create complex
7
+ ETL flows.
8
+
9
+ This macro can help by taking an empty table, and populating it with data
10
+ according to the variable types and formats.
11
+
12
+ TODO:
13
+ @li Consider dates, datetimes, times, integers etc
14
+
15
+ Usage:
16
+
17
+ proc sql;
18
+ create table work.example(
19
+ TX_FROM float format=datetime19.,
20
+ DD_TYPE char(16),
21
+ DD_SOURCE char(2048),
22
+ DD_SHORTDESC char(256),
23
+ constraint pk primary key(tx_from, dd_type,dd_source),
24
+ constraint nnn not null(DD_SHORTDESC)
25
+ );
26
+ %mp_makedata(work.example)
27
+
28
+ @param [in] libds The empty table (libref.dataset) in which to create data
29
+ @param [out] obs= (500) The maximum number of records to create. The table
30
+ is sorted with nodup on the primary key, so the actual number of records may
31
+ be lower than this.
32
+
33
+ <h4> SAS Macros </h4>
34
+ @li mf_getuniquename.sas
35
+ @li mf_getvarlen.sas
36
+ @li mf_getvarlist.sas
37
+ @li mf_islibds.sas
38
+ @li mf_nobs.sas
39
+ @li mp_getcols.sas
40
+ @li mp_getpk.sas
41
+
42
+ <h4> Related Macros </h4>
43
+ @li mp_makedata.test.sas
44
+
45
+ @version 9.2
46
+ @author Allan Bowe
47
+
48
+ **/
49
+
50
+ %macro mp_makedata(libds
51
+ ,obs=500
52
+ ,seed=1
53
+ )/*/STORE SOURCE*/;
54
+
55
+ %local ds1 ds2 lib ds pk_fields i col charvars numvars ispk;
56
+
57
+ %if %mf_islibds(&libds)=0 %then %do;
58
+ %put &sysmacroname: Invalid libds (&libds) - should be library.dataset format;
59
+ %return;
60
+ %end;
61
+ %else %if %mf_nobs(&libds)>0 %then %do;
62
+ %put &sysmacroname: &libds has data, it will not be recreated;
63
+ %return;
64
+ %end;
65
+
66
+ /* set up temporary vars */
67
+ %let ds1=%mf_getuniquename(prefix=mp_makedatads1);
68
+ %let ds2=%mf_getuniquename(prefix=mp_makedatads2);
69
+ %let lib=%scan(&libds,1,.);
70
+ %let ds=%scan(&libds,2,.);
71
+
72
+ /* grab the primary key vars */
73
+ %mp_getpk(&lib,ds=&ds,outds=&ds1)
74
+
75
+ proc sql noprint;
76
+ select coalescec(pk_fields,'_all_') into: pk_fields from &ds1;
77
+
78
+ data &ds2;
79
+ if 0 then set &libds;
80
+ do _n_=1 to &obs;
81
+ %let charvars=%mf_getvarlist(&libds,typefilter=C);
82
+ %if &charvars ^= %then %do i=1 %to %sysfunc(countw(&charvars));
83
+ %let col=%scan(&charvars,&i);
84
+ /* create random value based on observation number and colum length */
85
+ &col=repeat(put(md5(cats(_n_)),$hex32.),%mf_getvarlen(&libds,&col)/32);
86
+ %end;
87
+
88
+ %let numvars=%mf_getvarlist(&libds,typefilter=N);
89
+ %if &numvars ^= %then %do i=1 %to %sysfunc(countw(&numvars));
90
+ %let col=%scan(&numvars,&i);
91
+ &col=_n_;
92
+ %end;
93
+ output;
94
+ end;
95
+ stop;
96
+ run;
97
+ proc sort data=&ds2 nodupkey;
98
+ by &pk_fields;
99
+ run;
100
+
101
+ proc append base=&libds data=&ds2;
102
+ run;
103
+
104
+ proc sql;
105
+ drop table &ds1, &ds2;
106
+
107
+ %mend mp_makedata;
@@ -0,0 +1,58 @@
1
+ /**
2
+ @file
3
+ @brief Generates an md5 expression for hashing a set of variables
4
+ @details This is the same algorithm used to hash records in
5
+ [Data Controller for SAS](https://datacontroller.io) (free for up
6
+ to 5 users).
7
+
8
+ It is not designed to be efficient - it is designed to be effective,
9
+ given the range of edge cases (large floating points, special missing
10
+ numerics, thousands of columns, very wide columns).
11
+
12
+ It can be used only in data step, eg as follows:
13
+
14
+ data _null_;
15
+ set sashelp.class;
16
+ hashvar=%mp_md5(cvars=name sex, nvars=age height weight);
17
+ put hashvar=;
18
+ run;
19
+
20
+ Unfortunately it will not run in SQL - it fails with the following message:
21
+
22
+ > The width value for HEX is out of bounds. It should be between 1 and 16
23
+
24
+ The macro will also cause errors if the data contains (non-special) missings
25
+ and the (undocumented) `options dsoptions=nonote2err;` is in effect.
26
+
27
+ This can be avoided in two ways:
28
+
29
+ @li Global option: `options dsoptions=nonote2err;`
30
+ @li Data step option: `data YOURLIB.YOURDATASET /nonote2err;`
31
+
32
+ @param cvars= Space seperated list of character variables
33
+ @param nvars= Space seperated list of numeric variables
34
+
35
+ <h4> Related Programs </h4>
36
+ @li mp_init.sas
37
+
38
+ @version 9.2
39
+ @author Allan Bowe
40
+ **/
41
+
42
+ %macro mp_md5(cvars=,nvars=);
43
+ %local i var sep;
44
+ put(md5(
45
+ %do i=1 %to %sysfunc(countw(&cvars));
46
+ %let var=%scan(&cvars,&i,%str( ));
47
+ &sep put(md5(trim(&var)),$hex32.)
48
+ %let sep=!!;
49
+ %end;
50
+ %do i=1 %to %sysfunc(countw(&nvars));
51
+ %let var=%scan(&nvars,&i,%str( ));
52
+ /* multiply by 1 to strip precision errors (eg 0 != 0) */
53
+ /* but ONLY if not missing, else will lose any special missing values */
54
+ &sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.)
55
+ %let sep=!!;
56
+ %end;
57
+ ),$hex32.)
58
+ %mend mp_md5;
@@ -0,0 +1,43 @@
1
+ /**
2
+ @file
3
+ @brief Logs a message in a dataset every time it is invoked
4
+ @details If the dataset does not exist, it is created.
5
+ Usage:
6
+
7
+ %mp_perflog(started)
8
+ %mp_perflog()
9
+ %mp_perflog(startanew,libds=work.newdataset)
10
+ %mp_perflog(finished,libds=work.newdataset)
11
+ %mp_perflog(finished)
12
+
13
+
14
+ @param label Provide label to go into the control dataset
15
+ @param libds= Provide a dataset in which to store performance stats. Default
16
+ name is <code>work.mp_perflog</code>;
17
+
18
+ @version 9.2
19
+ @author Allan Bowe
20
+ @source https://github.com/sasjs/core
21
+
22
+ **/
23
+
24
+ %macro mp_perflog(label,libds=work.mp_perflog
25
+ )/*/STORE SOURCE*/;
26
+
27
+ %if not (%mf_existds(&libds)) %then %do;
28
+ data &libds;
29
+ length sysjobid $10 label $256 dttm 8.;
30
+ format dttm datetime19.3;
31
+ call missing(of _all_);
32
+ stop;
33
+ run;
34
+ %end;
35
+
36
+ proc sql;
37
+ insert into &libds
38
+ set sysjobid="&sysjobid"
39
+ ,label=symget('label')
40
+ ,dttm=%sysfunc(datetime());
41
+ quit;
42
+
43
+ %mend mp_perflog;
@@ -0,0 +1,88 @@
1
+ /**
2
+ @file
3
+ @brief Enables previous observations to be re-instated
4
+ @details Remembers the last X observations by storing them in a hash table.
5
+ Is a convenience over the use of lag() or retain, when an entire observation
6
+ needs to be restored.
7
+
8
+ This macro will also restore automatic variables (such as _n_ and _error_).
9
+
10
+ Example Usage:
11
+
12
+ data example;
13
+ set sashelp.class;
14
+ calc_var=_n_*3;
15
+ %* initialise hash and save from PDV ;
16
+ %mp_prevobs(INIT,history=2)
17
+ if _n_ =10 then do;
18
+ %* fetch previous but 1 record;
19
+ %mp_prevobs(FETCH,-2)
20
+ put _n_= name= age= calc_var=;
21
+ %* fetch previous record;
22
+ %mp_prevobs(FETCH,-1)
23
+ put _n_= name= age= calc_var=;
24
+ %* reinstate current record ;
25
+ %mp_prevobs(FETCH,0)
26
+ put _n_= name= age= calc_var=;
27
+ end;
28
+ run;
29
+
30
+ Result:
31
+
32
+ <img src="https://imgur.com/PSjHoET.png" alt="mp_prevobs sas" width="400"/>
33
+
34
+ Credit is made to `data _null_` for authoring this very helpful paper:
35
+ https://www.lexjansen.com/pharmasug/2008/cc/CC08.pdf
36
+
37
+ @param action Either FETCH a current or previous record, or INITialise.
38
+ @param record The relative (to current) position of the previous observation
39
+ to return.
40
+ @param history= The number of records to retain in the hash table. Default=5
41
+ @param prefix= the prefix to give to the variables used to store the hash name
42
+ and index. Default=mp_prevobs
43
+
44
+ @version 9.2
45
+ @author Allan Bowe
46
+
47
+ **/
48
+
49
+ %macro mp_prevobs(action,record,history=5,prefix=mp_prevobs
50
+ )/*/STORE SOURCE*/;
51
+ %let action=%upcase(&action);
52
+ %let prefix=%upcase(&prefix);
53
+ %let record=%eval((&record+0) * -1);
54
+
55
+ %if &action=INIT %then %do;
56
+
57
+ if _n_ eq 1 then do;
58
+ attrib &prefix._VAR length=$64;
59
+ dcl hash &prefix._HASH(ordered:'Y');
60
+ &prefix._KEY=0;
61
+ &prefix._HASH.defineKey("&prefix._KEY");
62
+ do while(1);
63
+ call vnext(&prefix._VAR);
64
+ if &prefix._VAR='' then leave;
65
+ if &prefix._VAR eq "&prefix._VAR" then continue;
66
+ else if &prefix._VAR eq "&prefix._KEY" then continue;
67
+ &prefix._HASH.defineData(&prefix._VAR);
68
+ end;
69
+ &prefix._HASH.defineDone();
70
+ end;
71
+ /* this part has to happen before FETCHing */
72
+ &prefix._KEY+1;
73
+ &prefix._rc=&prefix._HASH.add();
74
+ if &prefix._rc then putlog 'adding' &prefix._rc=;
75
+ %if &history>0 %then %do;
76
+ if &prefix._key>&history+1 then
77
+ &prefix._HASH.remove(key: &prefix._KEY - &history - 1);
78
+ if &prefix._rc then putlog 'removing' &prefix._rc=;
79
+ %end;
80
+ %end;
81
+ %else %if &action=FETCH %then %do;
82
+ if &record>&prefix._key then putlog "Not enough records in &Prefix._hash yet";
83
+ else &prefix._rc=&prefix._HASH.find(key: &prefix._KEY - &record);
84
+ if &prefix._rc then putlog &prefix._rc= " when fetching " &prefix._KEY=
85
+ "with record &record and " _n_=;
86
+ %end;
87
+
88
+ %mend mp_prevobs;
@@ -0,0 +1,90 @@
1
+ /**
2
+ @file
3
+ @brief Returns all children from a hierarchy table for a specified parent
4
+ @details Where data stores hierarchies in a simple parent / child mapping,
5
+ it is not always straightforward to extract all the children for a
6
+ particular parent. This problem is known as a recursive self join. This
7
+ macro will extract all the descendents for a parent.
8
+ Usage:
9
+
10
+ data have;
11
+ p=1;c=2;output;
12
+ p=2;c=3;output;
13
+ p=2;c=4;output;
14
+ p=3;c=5;output;
15
+ p=6;c=7;output;
16
+ p=8;c=9;output;
17
+ run;
18
+
19
+ %mp_recursivejoin(base_ds=have
20
+ ,outds=want
21
+ ,matchval=1
22
+ ,parentvar=p
23
+ ,childvar=c
24
+ )
25
+
26
+ @param base_ds= base table containing hierarchy (not modified)
27
+ @param outds= the output dataset to create with the generated hierarchy
28
+ @param matchval= the ultimate parent from which to filter
29
+ @param parentvar= name of the parent variable
30
+ @param childvar= name of the child variable (should be same type as parent)
31
+ @param mdebug= set to 1 to prevent temp tables being dropped
32
+
33
+
34
+ @returns outds contains the following variables:
35
+ - level (0 = top level)
36
+ - &parentvar
37
+ - &childvar (null if none found)
38
+
39
+ @version 9.2
40
+ @author Allan Bowe
41
+
42
+ **/
43
+
44
+ %macro mp_recursivejoin(base_ds=
45
+ ,outds=
46
+ ,matchval=
47
+ ,parentvar=
48
+ ,childvar=
49
+ ,iter= /* reserved for internal / recursive use by the macro itself */
50
+ ,maxiter=500 /* avoid infinite loop */
51
+ ,mDebug=0);
52
+
53
+ %if &iter= %then %do;
54
+ proc sql;
55
+ create table &outds as
56
+ select 0 as level,&parentvar, &childvar
57
+ from &base_ds
58
+ where &parentvar=&matchval;
59
+ %if &sqlobs.=0 %then %do;
60
+ %put NOTE: &sysmacroname: No match for &parentvar=&matchval;
61
+ %return;
62
+ %end;
63
+ %let iter=1;
64
+ %end;
65
+ %else %if &iter>&maxiter %then %return;
66
+
67
+ proc sql;
68
+ create table _data_ as
69
+ select &iter as level
70
+ ,curr.&childvar as &parentvar
71
+ ,base_ds.&childvar as &childvar
72
+ from &outds curr
73
+ left join &base_ds base_ds
74
+ on curr.&childvar=base_ds.&parentvar
75
+ where curr.level=%eval(&iter.-1)
76
+ & curr.&childvar is not null;
77
+ %local append_ds; %let append_ds=&syslast;
78
+ %local obs; %let obs=&sqlobs;
79
+ insert into &outds select distinct * from &append_ds;
80
+ %if &mdebug=0 %then drop table &append_ds;;
81
+
82
+ %if &obs %then %do;
83
+ %mp_recursivejoin(iter=%eval(&iter.+1)
84
+ ,outds=&outds,parentvar=&parentvar
85
+ ,childvar=&childvar
86
+ ,base_ds=&base_ds
87
+ )
88
+ %end;
89
+
90
+ %mend mp_recursivejoin;
@@ -0,0 +1,151 @@
1
+ /**
2
+ @file
3
+ @brief Performs a text substitution on a file
4
+ @details Performs a find and replace on a file, either in place or to a new
5
+ file. Can be used on files where lines are longer than 32767.
6
+
7
+ Works by reading in the file byte by byte, then marking the beginning and end
8
+ of each matched string, before finally doing the replace.
9
+
10
+ Full credit for this highly efficient and syntactically satisfying SAS logic
11
+ goes to [Bartosz Jabłoński](https://www.linkedin.com/in/yabwon), founder of
12
+ the [SAS Packages](https://github.com/yabwon/SAS_PACKAGES) framework.
13
+
14
+ Usage:
15
+
16
+ %let file="%sysfunc(pathname(work))/file.txt";
17
+ %let str=replace/me;
18
+ %let rep=with/this;
19
+ data _null_;
20
+ file &file;
21
+ put 'blahblah';
22
+ put "blahblah&str.blah";
23
+ put 'blahblahblah';
24
+ run;
25
+ %mp_replace(&file, findvar=str, replacevar=rep)
26
+ data _null_;
27
+ infile &file;
28
+ input;
29
+ list;
30
+ run;
31
+
32
+ Note - if you are running a version of SAS that will allow the io package in
33
+ LUA, you can also use this macro: mp_gsubfile.sas
34
+
35
+ @param infile The QUOTED path to the file on which to perform the substitution
36
+ @param findvar= Macro variable NAME containing the string to search for
37
+ @param replacevar= Macro variable NAME containing the replacement string
38
+ @param outfile= (0) Optional QUOTED path to the adjusted output file (to
39
+ avoid overwriting the first file).
40
+
41
+ <h4> SAS Macros </h4>
42
+ @li mf_getuniquefileref.sas
43
+ @li mf_getuniquename.sas
44
+
45
+ <h4> Related Macros </h4>
46
+ @li mp_chop.sas
47
+ @li mp_gsubfile.sas
48
+ @li mp_replace.test.sas
49
+
50
+ @version 9.4
51
+ @author Bartosz Jabłoński
52
+ @author Allan Bowe
53
+ **/
54
+
55
+ %macro mp_replace(infile,
56
+ findvar=,
57
+ replacevar=,
58
+ outfile=0
59
+ )/*/STORE SOURCE*/;
60
+
61
+ %local inref dttm ds1;
62
+ %let inref=%mf_getuniquefileref();
63
+ %let outref=%mf_getuniquefileref();
64
+ %if &outfile=0 %then %let outfile=&infile;
65
+ %let ds1=%mf_getuniquename(prefix=allchars);
66
+ %let ds2=%mf_getuniquename(prefix=startmark);
67
+
68
+ /* START */
69
+ %let dttm=%sysfunc(datetime());
70
+
71
+ filename &inref &infile lrecl=1 recfm=n;
72
+
73
+ data &ds1;
74
+ infile &inref;
75
+ input sourcechar $char1. @@;
76
+ format sourcechar hex2.;
77
+ run;
78
+
79
+ data &ds2;
80
+ /* set find string to length in bytes to cover trailing spaces */
81
+ length string $ %length(%superq(&findvar));
82
+ string =symget("&findvar");
83
+ drop string;
84
+
85
+ firstchar=char(string,1);
86
+ findlen=lengthm(string); /* <- for trailing bytes */
87
+
88
+ do _N_=1 to nobs;
89
+ set &ds1 nobs=nobs point=_N_;
90
+ if sourcechar=firstchar then do;
91
+ pos=1;
92
+ s=0;
93
+ do point=_N_ to min(_N_ + findlen -1,nobs);
94
+ set &ds1 point=point;
95
+ if sourcechar=char(string, pos) then s + 1;
96
+ else goto _leave_;
97
+ pos+1;
98
+ end;
99
+ _leave_:
100
+ if s=findlen then do;
101
+ START =_N_;
102
+ _N_ =_N_+ s - 1;
103
+ STOP =_N_;
104
+ output;
105
+ end;
106
+ end;
107
+ end;
108
+ stop;
109
+ keep START STOP;
110
+ run;
111
+
112
+ data &ds1;
113
+ declare hash HS(dataset:"&ds2(keep=start)");
114
+ HS.defineKey("start");
115
+ HS.defineDone();
116
+ declare hash HE(dataset:"&ds2(keep=stop)");
117
+ HE.defineKey("stop");
118
+ HE.defineDone();
119
+ do until(eof);
120
+ set &ds1 end=eof curobs =n;
121
+ start = ^HS.check(key:n);
122
+ stop = ^HE.check(key:n);
123
+ length strt $ 1;
124
+ strt =put(start,best. -L);
125
+ retain out 1;
126
+ if out then output;
127
+ if start then out=0;
128
+ if stop then out=1;
129
+ end;
130
+ stop;
131
+ keep sourcechar strt;
132
+ run;
133
+
134
+ filename &outref &outfile recfm=n;
135
+
136
+ data _null_;
137
+ length replace $ %length(%superq(&replacevar));
138
+ replace=symget("&replacevar");
139
+ file &outref;
140
+ do until(eof);
141
+ set &ds1 end=eof;
142
+ if strt ="1" then put replace char.;
143
+ else put sourcechar char1.;
144
+ end;
145
+ stop;
146
+ run;
147
+
148
+ /* END */
149
+ %put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
150
+
151
+ %mend mp_replace;
@@ -0,0 +1,27 @@
1
+ /**
2
+ @file
3
+ @brief Reset when an err condition occurs
4
+ @details When building apps, sometimes an operation must be attempted that
5
+ can cause an err condition. There is no try catch in SAS! So the err state
6
+ must be caught and reset.
7
+
8
+ This macro attempts to do that reset.
9
+
10
+ @version 9.2
11
+ @author Allan Bowe
12
+
13
+ **/
14
+
15
+ %macro mp_reseterror(
16
+ )/*/STORE SOURCE*/;
17
+
18
+ options obs=max replace nosyntaxcheck;
19
+ %let syscc=0;
20
+
21
+ %if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
22
+ data _null_;
23
+ rc=stpsrvset('program error', 0);
24
+ run;
25
+ %end;
26
+
27
+ %mend mp_reseterror;
@@ -0,0 +1,39 @@
1
+ /**
2
+ @file
3
+ @brief Reset an option to original value
4
+ @details Inspired by the SAS Jedi -
5
+ https://blogs.sas.com/content/sastraining/2012/08/14/jedi-sas-tricks-reset-sas-system-options
6
+
7
+ Called as follows:
8
+
9
+ options obs=30 ps=max;
10
+ %mp_resetoption(OBS)
11
+ %mp_resetoption(PS)
12
+
13
+
14
+ @param [in] option the option to reset
15
+
16
+ @version 9.2
17
+ @author Allan Bowe
18
+
19
+ **/
20
+
21
+ %macro mp_resetoption(option /* the option to reset */
22
+ )/*/STORE SOURCE*/;
23
+
24
+ %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
25
+ data _null_;
26
+ length code $1500;
27
+ startup=getoption("&option",'startupvalue');
28
+ current=getoption("&option");
29
+ if startup ne current then do;
30
+ code =cat('OPTIONS ',getoption("&option",'keyword','startupvalue'),';');
31
+ putlog "NOTE: Resetting system option: " code ;
32
+ call execute(code );
33
+ end;
34
+ run;
35
+ %end;
36
+ %else %do;
37
+ %put &sysmacroname: reset option feature unavailable on &sysvlong;
38
+ %end;
39
+ %mend mp_resetoption;