Compare commits

...

4 Commits

Author SHA1 Message Date
Bart Jablonski (yabwon)
df04e48656 The GSM package [ver. 0.19]
The `GSM` package [ver. 0.19]

- The code file parsing modified.
- A `lineEnd=` parameter added.
- The `trim=` parameter deprecated.
- A warning about the `/*%` text changed into a note.
- Documentation updated.

hash: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
2022-03-13 20:43:14 +01:00
Bart Jablonski (yabwon)
76c7793e34 The GSM package [ver. 0.18]
The GSM package [ver. 0.18]

- a bug fix in file scraping fixed

hash: 8D730316043A6523A3AF2AA15D2820BB75A46E06307F2B8916D30AC102AEE31D
2022-03-07 16:37:15 +01:00
Bart Jablonski (yabwon)
cc6528bbeb Package macroArray, version 1.0
Package **macroArray**, version 1.0:

- Update in `%mcHashTable()` macro.
- New macro `%mcDictionary()` emulating dictionaries in macro language.
- Doc. updated.
2022-02-17 14:20:12 +01:00
Bart Jablonski (yabwon)
2bb633a55b Updates in documentation.
Updates in documentation:
- Getting_Started_with_SAS_Packages.pdf
- SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf
2022-01-24 16:38:32 +01:00
9 changed files with 335 additions and 36 deletions

View File

@@ -122,7 +122,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
- **macroArray**\[0.9\], implementation of an array concept in a macrolanguage, e.g.
- **macroArray**\[1.0\], implementation of an array concept in a macrolanguage, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -141,7 +141,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
which = 1:H:2
);
```
SHA256 digest for macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
SHA256 digest for macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
@@ -168,12 +168,12 @@ SHA256 digest for BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B322
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
- **GSM** (Generate Secure Macros)\[0.17\], package allows
- **GSM** (Generate Secure Macros)\[0.19\], package allows
to create secured macros stored in SAS Proc FCMP functions.
The dataset with functions can be shared between different operating systems
and allows to generate macros on site without showing their code.
SHA256 digest for GSM: 3B70D8C31F02CB2B6AC47CC1DB3EC9E462796226CBFF519936AF5EEDB0C46B8F
SHA256 digest for GSM: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")

View File

@@ -65,7 +65,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
---
- **macroArray**\[0.9\], implementation of an array concept in a macro language, e.g.
- **macroArray**\[1.0\], implementation of an array concept in a macro language, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -84,7 +84,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
which = 1:H:2
);
```
SHA256 digest for macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
SHA256 digest for macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
@@ -114,12 +114,12 @@ SHA256 digest for BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B322
---
- **GSM** (Generate Secure Macros)\[0.17\], package allows
- **GSM** (Generate Secure Macros)\[0.19\], package allows
to create secured macros stored in SAS Proc FCMP functions.
The dataset with functions can be shared between different operating systems
and allows to generate macros on site without showing their code.
SHA256 digest for GSM: 3B70D8C31F02CB2B6AC47CC1DB3EC9E462796226CBFF519936AF5EEDB0C46B8F
SHA256 digest for GSM: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")

View File

@@ -1,3 +1,12 @@
/* 20220307 */
GSM: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
/* 20220307 */
GSM: 8D730316043A6523A3AF2AA15D2820BB75A46E06307F2B8916D30AC102AEE31D
/* 20220217 */
macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
/* 20220113 */
BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B3228987B6F74857
DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB81444ABB

View File

@@ -8,7 +8,7 @@
---
# The GSM package [ver. 0.17] <a name="gsm-package"></a> ###############################################
# The GSM package [ver. 0.19] <a name="gsm-package"></a> ###############################################
The **GSM** (a.k.a. *Generate Secure Macros*) package allows
to create secured macros stored in SAS Proc FCMP functions.
@@ -54,8 +54,33 @@ Recording of presentation with "how it works" description, in Polish, is avaliab
```
- Share generated `ZIP` file (unzip and run the code).
*Limitations:*
Single macro file cannot be longer than 32760 bytes.
**Limitations:**
- Single macro file cannot be longer than 32760 bytes.
- Multiline text variable. Consider the following code text file:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%macro~test()/SECURE;~#@
data~test;~#@
a~=~"abc~#@
~#@
def";~#@
put~a~hex20.;~#@
run;~#@
%mend~test;~#@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where `~` symbols the space character,
`#` symbols the carriage return (`0D`),
and `@` symbols the line feed (`0A`).
The code file is scanned and inserted into
the `resolve()` function argument in a "byte by byte"
fashion hence also the "end of line" characters are included.
As the result value of variable `a` will be:
`a = "abc~#@~#@def"`.
If you want to use the `GSM` package avoid
such "style" of coding in your macros.
---
@@ -69,7 +94,7 @@ Required SAS Components:
* SAS package generated by generatePackage, version 20220113 *
The SHA256 hash digest for package GSM:
`3B70D8C31F02CB2B6AC47CC1DB3EC9E462796226CBFF519936AF5EEDB0C46B8F`
`F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF`
## >>> `%GSM()` macro: <<< <a name="gsm-macro"></a> #######################
@@ -92,7 +117,7 @@ be added to the macro definition. See the example:
As a result a zip file, containing dataset with functions and
code to be executed on site, is generated.
code to be executed on site, is generated.
Since encrypted code is stored in a SAS dataset it has
no limitation in sharing between operating systems (like catalogs have).
@@ -117,6 +142,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
<,outpath=>
<,encodingRestricted=>
<,secret=>
<,lineEnd=>
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -125,10 +151,6 @@ The basic syntax is the following, the `<...>` means optional parameters:
1. `path` - *Required*, indicates a directory which contains files with macros.
Only files with `sas` extension are used.
* `trim=` - *Optional*, the default value is `0`.
If set to `1` then lines of macro code are trimmed.
If set to `2` then lines of macro code are stripped.
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
Names the dataset which will contain generated functions.
@@ -151,8 +173,20 @@ The basic syntax is the following, the `<...>` means optional parameters:
Required to execute the `resolve()` function.
User who do not know the value will not be able
to run the `_maxro_XX_()` function.
---
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
line feed, carriage return, or both, or a space be inserted
at the end of line in the intermediate code file that is generated.
Value has to be hexadecimal code (_NOT_ null),
since the value is resolved as `"&lineEnd."x`, so use e.g.
`0A` for line feed, `0D` for carriage return,
`0D0A` for both, and `20` for space.
* `trim=` - *Deprecated*, the default value is `0`.
*Kept for backward compatibility.*
---
### Example: ###################################################################
@@ -197,8 +231,7 @@ run;
%GSM(&path., cmplib=work.myMacros)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## >>> `%GSMpck_makeFCMPcode()` macro: <<< <a name="gsmpck-makefcmpcode-macro"></a> #######################
## >>> `%GSMpck_makeFCMPcode()` macro: <<< <a name="GSMpck-makeFCMPcode-macro"></a> #######################
The `%GSMpck_makeFCMPcode()` macro is an internal macro of
the **GSM** (a.k.a. *Generate Secure Macros*) package.
@@ -219,11 +252,11 @@ The basic syntax is the following, the `<...>` means optional parameters:
%GSMpck_makeFCMPcode(
path
,number
<,trim=0>
<,outlib=work.generateMacros.secure>
<,source2=>
<,fileNameCode=FNC>
<,secret=123456789>
<,lineEnd=0A>
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -234,9 +267,6 @@ The basic syntax is the following, the `<...>` means optional parameters:
2. `number` - *Required*, a sequential number.
* `trim=` - *Optional*, the default value is `0`.
If set to `1` then lines of macro code are trimmed.
If set to `2` then lines of macro code are stripped.
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
Names the dataset which will contain generated functions.
@@ -253,6 +283,17 @@ The basic syntax is the following, the `<...>` means optional parameters:
function. User who do not know the value will not be able
to run the `_maxro_XX_()` function.
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
line feed, carriage return, or both, or a space be inserted
at the end of line in the intermediate code file that is generated.
Value has to be hexadecimal code (_NOT_ null),
since the value is resolved as `"&lineEnd."x`, so use e.g.
`0A` for line feed, `0D` for carriage return,
`0D0A` for both, and `20` for space.
* `trim=` - *Deprecated*, the default value is `0`.
*Kept for backward compatibility.*
---

Binary file not shown.

View File

@@ -10,6 +10,7 @@
* [`%do_over3()` macro](#do-over3-macro)
* [`%make_do_over()` macro](#make-do-over-macro)
* [`%mcHashTable()` macro](#mchashtable-macro)
* [`%mcDictionary()` macro](#mcdictionary-macro)
* [`%QzipArrays()` macro](#qziparrays-macro)
* [`%zipArrays()` macro](#ziparrays-macro)
* [`%sortMacroArray()` macro](#sortmacroarray-macro)
@@ -18,7 +19,7 @@
---
# The macroArray package [ver. 0.9] <a name="macroarray-package"></a> ###############################################
# The macroArray package [ver. 1.0] <a name="macroarray-package"></a> ###############################################
The **macroArray** package implements a macro array facility:
- `%array()`,
@@ -30,6 +31,7 @@ The **macroArray** package implements a macro array facility:
- `%mcHashTable()`,
- `%zipArrays()`,
- `%sortMacroArray()`,
- `%mcDictionary()`,
- etc.
The set of macros, which emulates classic
@@ -64,10 +66,11 @@ Package contains:
7. macro do_over2
8. macro do_over3
9. macro make_do_over
10. macro mchashtable
11. macro sortmacroarray
12. macro qziparrays
13. macro ziparrays
10. macro mcdictionary
11. macro mchashtable
12. macro qziparrays
13. macro sortmacroarray
14. macro ziparrays
Required SAS Components:
*Base SAS Software*
@@ -75,7 +78,7 @@ Required SAS Components:
*SAS package generated by generatePackage, version 20220113.*
The SHA256 hash digest for package macroArray:
`833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA`
`DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2`
---
# Content description ############################################################################################
@@ -1210,7 +1213,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
macrovariables named like "`&H._`" are deleted.
* `HASH=` - *Optional*, indicates which hashing algorithms should be used,
available values are `CRC32` or `MD5`, the `CRC32` is the default.
available values are `CRC32` or `MD5`, the `CRC32` is the default.
---
@@ -1391,7 +1394,7 @@ See examples below to see use cases.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 2.** Populate macro hash table from a dataset.
**EXAMPLE 3.** Populate macro hash table from a dataset.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(CLASS)
@@ -1419,7 +1422,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 3.** Data portion may require quoting and un-quoting..
**EXAMPLE 4.** Data portion may require quoting and un-quoting..
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(CODE)
@@ -1436,7 +1439,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 4.** Longer lists.
**EXAMPLE 5.** Longer lists.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%let size = 1000;
@@ -1509,7 +1512,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 5.** Forbidden names.
**EXAMPLE 6.** Forbidden names.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable()
@@ -1519,7 +1522,7 @@ run;
%mcHashTable(ABCDEFGHIJKLMNOP) %* good;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 5.** Hashing algorithms.
**EXAMPLE 7.** Hashing algorithms.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(H1,DCL,HASH=MD5)
@@ -1528,6 +1531,252 @@ run;
---
## >>> `%mcDictionary()` macro: <<< <a name="mcdictionary-macro"></a> #######################
The `%mcDictionary()` macro provided in the package
is designed to facilitate the idea of a "macro dictionary"
concept, i.e. *a list of macrovariables with common prefix
and suffixes generated as a hash digest* which allows
to use values other than integers as indexes.
The `%mcDictionary()` macro allows to generate other macros
which behaves like a dictionary. See examples below.
The `%mcDictionary()` macro executes like a pure macro code.
### SYNTAX: ###################################################################
The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%mcDictionary(
H
<,METHOD>
)
~~~~~~~~~~~~~~~~~~~~~~~
**Arguments description**:
1. `H` - *Required*, a dictionary macro name and a declaration/definition,
e.g. `mcDictionary(HT)`. It names a macro which is generated by
the `%mcDictionary()` macro. Provided name cannot be empty
or an underscore (`_`). No longer than *16* characters.
2. `METHOD` - *Optional*, if empty (or DECLARE or DCL) then the code of
a macro dictionary is compiled.
If `DELETE` then the macro dictionary named by `H` and all
macrovariables named like "`&H._`" are deleted.
---
### THE CREATED MACRO `%&H.()`: ####################################################
The created macro imitates behaviour of a dictionary.
The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%&H.(
METHOD
<,KEY=>
<,DATA=>
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Arguments description**:
1. `METHOD` - *Required*, indicate what behaviour should be executed.
Allowed values are:
- `ADD`, adds key and data portion to the macro dictionary,
*multiple data portions* are NOT available for one key.
- `FIND`, tests if given key exists in the macro dictionary
and, if yes, returns data value associated with the key.
For multiple data portions see the `data=` parameter.
- `CHECK`, returns indicator if the key exists in dictionary.
- `DEL`, removes key and data portion from the macro dictionary.
- `LIST`, prints out a dictionary to the log.
- `CLEAR` removes all data and keys values.
* `KEY=` - *Optional*, provides key value for `ADD`, `FIND`, `CHECK`
and `DEL` methods.
Leading and trimming spaces are removed from the value.
The `MD5(...)` function is used to generate the hash.
Default value is `_`.
* `DATA=` - *Optional*, provides data value for the `ADD` method.
Default value is blank.
When macro is executed and when data are added the following types of
*global* macrovariables are created:
- `&H._########_K`,
- `&H._########_V`,
- `&H._KEYSNUM`.
The `#` represents value generated by the `MD5(...)` function for the given key.
The first type keeps information about the key.
The second type keeps information about the value of a given key
The third type keeps the number of unique values of the key.
See examples below to see use cases.
---
### EXAMPLES AND USECASES: ####################################################
**EXAMPLE 1.** Basic use-case.
Creating macro dictionary, macro `Dict` is generated.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcDictionary(Dict)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add elements to the `Dict`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%Dict(ADD,key=x,data=17)
%Dict(ADD,key=y y,data=42)
%Dict(ADD,key=z z z,data=303)
%put _user_;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add some duplicates for the key x.
See macrovariables created.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%Dict(ADD,key=x,data=18)
%put _user_;
%Dict(ADD,key=x,data=19)
%put _user_;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Check for the key `x` and non existing key `t`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%put ##%Dict(CHECK,key=x)##;
%put ##%Dict(CHECK,key=t)##;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prints data values for various keys.
Key `t` does not exist in the macrodictionary.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%put #%Dict(FIND,key=x)#;
%put #%Dict(FIND,key=y y)#;
%put #%Dict(FIND,key=z z z)#;
%put #%Dict(FIND,key=t)#;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
List dictionary content to the log.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%Dict(LIST);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Delete keys.
Key `t` does not exist in the macrodictionary.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%put #%Dict(DEL,key=z z z)#;
%put _user_;
%put #%Dict(DEL,key=t)#;
%put _user_;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Clear and delete macro dictionary `Dict`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%Dict(CLEAR)
%put _user_;
%mcDictionary(Dict,DELETE)
%put _user_;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 2.** Populate macro dictionary from a dataset.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcDictionary(CLASS)
%let t = %sysfunc(datetime());
data _null_;
set sashelp.class;
call execute('%CLASS(ADD,key=' !! name !! ',data=' !! age !! ')');
run;
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
%put _user_;
%CLASS(CLEAR)
%mcDictionary(CARS)
%let t = %sysfunc(datetime());
data _null_;
set sashelp.cars;
call execute('%CARS(ADD,key=' !! catx("|",make,model,type) !! ',data=' !! MPG_CITY !! ')');
run;
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
%put &=CARS_KEYSNUM.;
%CARS(LIST);
%CARS(CLEAR)
%put &=CARS_KEYSNUM.;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 3.** Data portion may require quoting and un-quoting..
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcDictionary(CODE)
%CODE(CLEAR)
%CODE(ADD,key=data, data=%str(data test; x = 42; run;))
%CODE(ADD,key=proc, data=%str(proc print; run;))
%CODE(ADD,key=macro,data=%nrstr(%put *****;))
%CODE(FIND,key=data)
%CODE(FIND,key=proc)
%unquote(%CODE(FIND,key=macro))
%CODE(LIST);
%mcDictionary(CODE,DELETE)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 4.** Longer lists.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%let size = 1000;
%mcDictionary(AAA)
%let t = %sysfunc(datetime());
data _null_;
do i = 1 to &size.;
call execute(cats('%AAA(ADD,key=A', i, ',data=', i, ')'));
end;
run;
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
%put &=AAA_KEYSNUM;
%AAA(CLEAR)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 5.** Forbidden names.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcDictionary()
%mcDictionary(_)
%mcDictionary(ABCDEFGHIJKLMNOPQ) %* bad;
%mcDictionary(ABCDEFGHIJKLMNOP) %* good;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---
## >>> `%QzipArrays()` macro: <<< <a name="qziparrays-macro"></a> #######################
The zipArrays() and QzipArrays() macros

Binary file not shown.