Compare commits

...

19 Commits

Author SHA1 Message Date
Bart Jablonski
c9b388b661 The BasePlus package [ver. 1.30.0]
The BasePlus package [ver. 1.30.0]

- new macro `%repList()` added
- doc. updated

SHA256 digest: `F*B91771D45C781B6806DBB44A3B491A0784D7698B9F3BBBE1A86EE5594834315F`
2023-09-19 17:43:54 +02:00
Bart Jablonski
82681a3f91 Update README.md 2023-09-12 12:50:28 +02:00
Bart Jablonski
cb4f82eac9 The macroArray package [ver. 1.1.0]
The macroArray package [ver. 1.1.0]

New parameter in the `%array()` macro:
* `q=` - *Optional*, indicates (when set to `1`) if the value be surrounded by quotes. It uses `quote(cats(...))` combo under the hood. Default value is `0`. Ignored for `macarray=M`.
2023-09-06 23:09:40 +02:00
Bart Jablonski
98e2125028 SAS Packages Framework, version 20230904
## SAS Packages Framework, version `20230904`

---

New features in this release are:
- in `%generatePackage()` macro - test for check of duplicated names of the same type was added to the package generation process.
- in `%loadPackage()` macro - User can now suppress running the `exec` type files during the loading process. Parameter name is `suppressExec=`.
- in `%helpPackage()` macro - User can now generate dataset `work.packageName_content` containing list of the package elements similar to the one printed in the log. Parameter name is `packageContentDS=`.

Documentation updated.

---

Packages regenerated with new version of the SPF:
- BasePlus package [ver. `1.29.1`]
- DFA package [ver. `0.5.6`]
- GSM package [ver. `0.21.1`]
- macroArray package [ver. `1.0.6`]
- SQLinDS package [ver. `2.2.7`]
- dynMacroArray package [ver. `0.2.6`]
2023-09-04 16:29:05 +02:00
Bart Jablonski
77d6b0a2e5 The BasePlus package [ver. 1.29.0]
The BasePlus package [ver. 1.29.0]

Three new macros:
- fmt
- infmt
- minclude

Documentation updated.

SHA256 for BasePlus: `F*9EEE4F4B99EA725B60141645AB6A50BFEBA32CE54848593F8D832D907D63CAD7`
2023-08-24 11:32:01 +02:00
Bart Jablonski
c1182ea8cb The GSM package [ver. 0.21.0]
The GSM package [ver. 0.21.0]

Changes:
- new debugging parameter `encrypt` added to the `%GSM()` macro
- annoying note on "automatic type conversion" fixed
2023-07-27 11:07:49 +02:00
Bart Jablonski
ddfac01483 The BasePlus package [ver. 1.26.1]
The BasePlus package [ver. 1.26.1]

Updates:
- the `%RainCloudPlot()` has new parameter: `catAxisValueAttrs`,
- documentation was updated (refreshed example with plot).

The SHA256 hash digest for package BasePlus:
`F*D6DC5AD1B60A92AD300B639B3C361C1F7846EB01E5AB35BF4FDDA6E783408172`
2023-06-02 11:42:12 +02:00
Bart Jablonski
d8c8cfc9e3 The BasePlus package [ver. 1.26.0]
# The BasePlus package [ver. 1.26.0]

### New Features:
Two new macros were introduces in the release:
 - `%findDSwithVarVal()`
 - `%getTitle()`

Documentation updated.
2023-06-01 17:49:48 +02:00
Bart Jablonski
c126e7c0a3 The BasePlus package [ver. 1.26.0]
# The BasePlus package [ver. 1.26.0]

### New Features:
Two new macros were introduces in the release:
 - `%findDSwithVarVal()`
 - `%getTitle()`

Documentation updated.
2023-06-01 17:04:12 +02:00
Bart Jablonski
e7883142b8 The BasePlus package [ver. 1.24.2]
The BasePlus package [ver. 1.24.2]

Updates:
- the `%RainCloudPlot()` has 2 new parameters: `catLabelAttrs` and `xLabelAttrs`,
- documentation was updated (new examples with plots), and
- some spellings were fixed.

The SHA256 hash digest for package BasePlus:
`F*2A4F3953EC56DB914024457F74286D565C23DCF220FF151040BDB704FD8DDB06`
2023-05-26 11:17:42 +02:00
Bart Jablonski
e55275d308 SAS Packages Framework, version 20230520
SAS Packages Framework, version 20230520

Fixes:
- Bug fixes for the "Additional Content" feature. In the `%loadPackageAddCnt()` and `%generatePackage()` macros lengths of the "file path" variables were extended.

Packages:
- The `BasePlus` package, version `1.24.1` was regenerated with latest version of the framework.
- The `%RainCloudPlot()` macro from the `BasePlus` packages was updated with new parameters (see the documentation).

Documentation:
- Documentation updated.
2023-05-20 17:23:53 +02:00
Bart Jablonski
72a77edb16 The BasePlus package [ver. 1.24.0]
The BasePlus package [ver. 1.24.0]

Six new utility macros for the BasePlus:
- `%letters()` - allows to print a list of Roman letters,
- `%filePath()` - from fileref returns path to a file,
- `%libPath()` - from libref  returns path to a library,
- `%workPath()` - returns path to the `WORK` library,
- `%translate()` - a wrapper to translate() function,
- `%tranwrd()` - a wrapper to tranwrd() function.

Documentation updated.
2023-05-03 23:04:41 +02:00
Bart Jablonski
dbe8dbc938 The BasePlus package [ver. 1.23.0]
The BasePlus package [ver. 1.23.0]

Three new utility macros for the BasePlus:
- `%intsList()` - prints a space separated list of integers,
- `%splitDSIntoBlocks()` - splits dataset into block of given size (and one[the last] possibly smaller)
- `%splitDSIntoParts()` - splits dataset into given number of parts (of approximately same size)

Macros `splitDSIntoBlocks` and `splitDSIntoParts` supports *BASE* and *SPDE* engines.

Documentation updated.
2023-04-19 16:38:57 +02:00
Bart Jablonski
9168f4b4f0 The BasePlus package [ver. 1.20.0]
The BasePlus package [ver. 1.20.0]

- New utility macro `%repeatTxt()` added.
- Documentation updated.
2023-04-17 14:57:29 +02:00
Bart Jablonski
2f5cb056b1 SAS Packages Framework, version 20230411
## **SAS Packages Framework**, version `20230411`.

---

Fixes:
- Bug fix for cherry picking. Cherry picking from already loaded package caused deletion of search paths to FCMP functions, Proto functions, Formats, and Informats. Also corresponding dataset for Proc Proto was deleted.
- Bug fix for Proc Proto C functions. The way how Proc Proto adds new portions of stored C functions caused that, if there were multiple directories with proto C functions all content was overwritten by the last one.

[Documentation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "Documentation") updated.

---

Packages regenerated with latest version of SAS Packages Framework:
- [BasePlus](https://github.com/SASPAC/baseplus "BasePlus") package [ver. 1.19.1]
- [DFA](https://github.com/SASPAC/dfa "DFA") package [ver. 0.5.5]
- dynMacroArray package [ver. 0.2.5]
- [GSM](https://github.com/SASPAC/gsm "GSM") package [ver. 0.20.5]
- [macroArray](https://github.com/SASPAC/macroarray "macroArray") package [ver. 1.0.5]
- [SQLinDS](https://github.com/SASPAC/sqlinds "SQLinDS") package [ver. 2.2.6]

---
2023-04-11 18:37:31 +02:00
Bart Jablonski
44be31bd84 Link to Warsaw IT Days 2023 presentation added
Link to "SAS Packages Framework - an easy code sharing medium for SAS" presentation at Warsaw IT Days 2023 added.
YT: https://youtu.be/T52Omisi0dk&t=0s
2023-04-04 11:54:39 +02:00
Bart Jablonski
227e522f5b The BasePlus package [ver. 1.19.0]
The BasePlus package [ver. 1.19.0]

New macro:
The `%dirsAndFiles()` macro allows to extract info about all files and subdirectories of a given `root` directory. The macro is based on Kurt Bremser's "*Talking to Your Host*" article presented at WUSS 2022 conference.
2023-04-01 22:27:41 +02:00
Bart Jablonski
9a3ff6a265 The SQLinDS package [ver. 2.2.5]
The SQLinDS package [ver. 2.2.5]

Mike Rhoads' article "Use the Full Power of SAS in Your Function-Style Macros" added to the additional content for the package.
2023-02-10 09:56:17 +01:00
Bart Jablonski
62a14b4560 SAS Packages Framework, version 20230207
SAS Packages Framework, version 20230207

News:
- "Additional Content" feature added to the framework.

Changes in the framework related to the new feature:
- new macro `%loadPackageAddCnt()`,
- modifications in the `%generatePackage()` macro,
- new parameter in `%loadPackage()` and `%installPackage()` macros,
- new code added in loading test.

Fixes:
- IML Modules loader utility macro rewritten,
- bug fixes.

Documentation:
- documentation updated,
- spelling fixes.
2023-02-07 17:51:24 +01:00
34 changed files with 3819 additions and 496 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 - 2022 Bartosz Jablonski
Copyright (c) 2019 - 2023 Bartosz Jablonski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

114
README.md
View File

@@ -14,7 +14,7 @@ In this repository we are presenting the **SAS Packages Framework** which allows
### Current version:
**The latest version** of SPF is **`20230112`**.
**The latest version** of SPF is **`20230904`**.
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
@@ -34,6 +34,8 @@ Videos presenting the SPF and packages, from various conferences and meetups (th
- ["Kod SASowy ukryty na widoku" - SAS dla Administratorów i Praktyków 2021](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s) (November 24th 2021, in Polish, ~34 minutes, technical presentation with details about the GSM package)
- ["A BasePlus Package for SAS" - SAS Explore 2022](https://communities.sas.com/t5/SAS-Explore-Presentations/A-BasePlus-Package-for-SAS/ta-p/838246 "SASexplore2022 communities.sas.com") (September 27th-29th 2022, ~28 minutes, technical presentation with details about the BasePlus package), alternative video at YouTube is [here](https://www.youtube.com/watch?v=-Poxkx5WfOQ "SASexplore2022 TouTube")
- ["SAS Packages - State of the Union" - SaSensei International Dojo No. 13](https://www.youtube.com/watch?v=1GEldZYQjj0&t=0s "SID no. 13") (November 10th 2022, ~50 minutes, general overview with the latest technical details)
- ["SAS Packages Framework - an easy code sharing medium for SAS" - Warsaw IT Days 2023](https://youtu.be/T52Omisi0dk&t=0s "Warsaw IT Days 2023") (March 31st 2023, ~60 minutes, general overview with technical details for user and developer)
---
@@ -49,7 +51,7 @@ The first step to use a package with the SAS Packages Framework:
- Create a folder for your packages, under Windows OS family e.g., `C:/SAS_PACKAGES` or under Linux/UNIX OS family e.g., `/home/<username>/SAS_PACKAGES`.
and then either:
Then either:
- Manually download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
- \[Optional\] Manually download the `<packageName>.zip` file into the local packages folder.
@@ -86,6 +88,13 @@ or do it pragmatically:
```sas
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit; /* enable the framework */
```
or (shorter) with:
```sas
filename SPFinit url "https://bit.ly/SPFinit";
%include SPFinit; /* enable the framework */
```
- Install the framework on your machine in the folder you created:
@@ -95,7 +104,7 @@ filename packages "<directory/containing/packages/>";
%installPackage(SPFinit) /* install the framework */
```
- And from now on run it like this:
- From now on run it like this:
```sas
filename packages "<directory/containing/packages/>";
@@ -107,7 +116,8 @@ filename packages "<directory/containing/packages/>";
```
---
The "Workshop video for the User" got outdated (in general). Newer version is comming soon, in the mean time see some of the vedeos from the "Recordings and Presentations" section above.
The "Workshop video for the User" got outdated (in general). Newer version is coming soon, in the mean time see some of the videos from the "Recordings and Presentations" section above.
(You can watch the workshop if you wish, link is working and some parts are still valid source of information e.g., "`ICE` loading" or "`disk` loading")
<s>[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y) \[May 6th, 2020\] [~86 minutes, outdated (installPackage macro was not there yet) but gives the idea how it works especially load, help, unload, ICEload, and other details]</s>
@@ -126,7 +136,7 @@ To create your own package:
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To") or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To")
The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parametera.
The SAS Packages Framework [(short) documentation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parameters.
---
@@ -136,7 +146,9 @@ The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_
### Updates worth mentioning:
**Update**\[December 12th, 2022\]**:** `CASLUDF` **typed for CASL user defined functions added to the framework. Utility macros for for loading content in proc IML and proc CAS added. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221212 "New Type and Utility macros"))**.
**Update**\[February 7th, 2023\]**:** `ADDCNT` ** type for *additional content* feature and ** `%loadPackageAddCnt()` **macro added to the framework. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20230207 "Additional Content"))**.
**Update**\[December 12th, 2022\]**:** `CASLUDF` ** type for CASL user defined functions added to the framework. Utility macros for for loading content in proc IML and proc CAS added. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221212 "New Type and Utility macros"))**.
**Update**\[November 21st, 2022\]**:** `%loadPackage()` **macro allows Cherry Picking of content (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221121 "Cherry Picking"))**.
@@ -168,97 +180,47 @@ If you find the SPF useful **share info** about it or **give it a [star](https:/
## Available packages:
**(!)** For "backward compatibility"/historical point of view the following packages are available under the `./packages` directory.
This section presents some example of available SAS packages.
**(!)** Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
**(!)** For "backward compatibility"/historical point of view the following packages are also available under the `./packages` directory in this repository.
Packages:
- **SQLinDS**\[2.2.4\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
```sas
data class;
set %SQL(select * from sashelp.class order by age);
run;
```
SHA256 digest for SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
- **SQLinDS**
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
[SQLinDS in SASPAC](https://github.com/SASPAC/sqlinds "SQLinDS in SASPAC")
[SQLinDS in SASPAC](https://github.com/SASPAC/sqlinds "SQLinDS in SASPAC")
- **DFA** (Dynamic Function Arrays)\[0.5.4\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
- **DFA** (Dynamic Function Arrays)
SHA256 digest for DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
[DFA in SASPAC](https://github.com/SASPAC/dfa "DFA in SASPAC")
[DFA in SASPAC](https://github.com/SASPAC/dfa "DFA in SASPAC")
- **macroArray**
- **macroArray**\[1.0.4\], implementation of an array concept in a macrolanguage, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
%macro test();
%do i = 1 %to 17;
%put &i.) %ABC(&i.);
%end;
%mend;
%test()
%let %ABC(13,i) = 99999; /* i = insert */
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
%do_over(ABC, phrase=%nrstr(
%put &_i_.%) %ABC(&_i_.);
),
which = 1:H:2
);
```
SHA256 digest for macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
[MacroArray in SASPAC](https://github.com/SASPAC/macroarray "MacroArray in SASPAC")
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
- **BasePlus**
[MacroArray in SASPAC](https://github.com/SASPAC/macroarray "MacroArray in SASPAC")
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
- **BasePlus**\[1.18.4\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```sas
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
call arrFill(42, myArray);
[BasePlus in SASPAC](https://github.com/SASPAC/baseplus "BasePlus in SASPAC")
rc = delDataset("DataSetToDrop");
- **GSM** (Generate Secure Macros)
string = catXFn("date9.", "#", myArray);
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
format x bool.;
[GSM in SASPAC](https://github.com/SASPAC/gsm "GSM in SASPAC")
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
- **dynMacroArray**
%rainCloudPlot(sashelp.cars,DriveTrain,Invoice)
%zipLibrary(sashelp,libOut=work)
%bpPIPE(ls -la ~/)
```
SHA256 digest for BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
[BasePlus in SASPAC](https://github.com/SASPAC/baseplus "BasePlus in SASPAC")
- **GSM** (Generate Secure Macros)\[0.20.4\], 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: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
[GSM in SASPAC](https://github.com/SASPAC/gsm "GSM in SASPAC")
- **dynMacroArray**\[0.2.4\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
SHA256 digest for dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
Development of this package is currently on hold.
### ======

View File

@@ -6,7 +6,7 @@
when empty the "packages" value is used */
)/secure
/*** HELP END ***/
des = 'Macro to list directories pointed by "packages" fileref, version 20230112. Run %extendPackagesFileref(HELP) for help info.'
des = 'Macro to list directories pointed by "packages" fileref, version 20230904. Run %extendPackagesFileref(HELP) for help info.'
;
%if %QUPCASE(&packages.) = HELP %then
@@ -22,7 +22,7 @@ des = 'Macro to list directories pointed by "packages" fileref, version 20230112
%put ### This is short help information for the `extendPackagesFileref` macro #;
%put #-----------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to list directories pointed by 'packages' fileref, version `20230112` #;
%put # Macro to list directories pointed by 'packages' fileref, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -102,4 +102,3 @@ filename packages list;
*/
/**/

View File

@@ -23,7 +23,7 @@
default value 1 means "delete tests work" */
)/ secure minoperator
/*** HELP END ***/
des = 'Macro to generate SAS packages, version 20230112. Run %generatePackage() for help info.'
des = 'Macro to generate SAS packages, version 20230904. Run %generatePackage() for help info.'
;
%if (%superq(filesLocation) = ) OR (%qupcase(&filesLocation.) = HELP) %then
%do;
@@ -38,7 +38,7 @@ des = 'Macro to generate SAS packages, version 20230112. Run %generatePackage()
%put ### This is short help information for the `generatePackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to generate SAS packages, version `20230112` #;
%put # Macro to generate SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -96,7 +96,7 @@ des = 'Macro to generate SAS packages, version 20230112. Run %generatePackage()
%end;
%put --- generatePackage START ---;
%local zipReferrence filesWithCodes _DESCR_ _LIC_ _DUMMY_ _RC_ _PackageFileref_;
%local zipReferrence filesWithCodes _DESCR_ _LIC_ _DUMMY_ _RC_ _PackageFileref_ additionalContent;
%let zipReferrence = _%sysfunc(datetime(), hex6.)_;
%let filesWithCodes = WORK._%sysfunc(datetime(), hex16.)_;
%let _DESCR_ = _%sysfunc(datetime(), hex6.)d;
@@ -491,6 +491,15 @@ DESCRIPTION END:
|
+-...
|
+-998_addcnt [additional content for the package, can be only one!, content of this
| | directory is copied "as is"]
| |
| +-arbitrary_file1 [an arbitrary file ]
| |
| +-subdirectory_with_files [an arbitrary directory with some files inside]
| |
| +-...
|
+-999_test [tests executed during package generation, XCMD options must be turned-on]
| |
| +-test1.sas [a file with a code for test1]
@@ -553,7 +562,9 @@ data &filesWithCodes.;
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA'
'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/
'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN'
'LAZYDATA' 'TEST' 'CASLUDF'))
'LAZYDATA' 'TEST' 'CASLUDF'
'ADDCNT'
))
then
do;
put "WARNING: Type " type 'is not yet supported.' /
@@ -561,30 +572,53 @@ data &filesWithCodes.;
"WARNING- No content from it will be used to generate the package." / " ";
goto ignoreFolder;
end;
/* if it is a directory then read its content */
if fileId then
do j = 1 to dnum(fileId); drop j;
file = dread(fileId, j);
if file NE lowcase(file) then
do;
put 'ERROR: File with code should be named ONLY with low case letters.';
put 'ERROR- Current value is: ' file;
lowcase_name = lowcase(file);
put 'ERROR- Try to use: ' lowcase_name;
put;
_abort_ + 1;
end;
fileshort = substr(file, 1, length(file) - 4); /* filename.sas -> filename */
if strip(reverse(file)) in: ('sas.') then output; /* ignore not ".sas" files */
else
do;
put "WARNING: Only *.sas files are supported." /
"WARNING- The file: " file "will be ignored." /
"WARNING- ";
end;
end;
/* if it is a directory then read its content... */
if fileId then
do;
/* ...but! do not use files from "additional content" directory */
if NOT (upcase(type) =: 'ADDCNT') then
do j = 1 to dnum(fileId); drop j;
file = dread(fileId, j);
if file NE lowcase(file) then
do;
put 'ERROR: File with code should be named ONLY with low case letters.';
put 'ERROR- Current value is: ' file;
lowcase_name = lowcase(file);
put 'ERROR- Try to use: ' lowcase_name;
put;
_abort_ + 1;
end;
fileshort = substr(file, 1, length(file) - 4); /* filename.sas -> filename */
if strip(reverse(file)) in: ('sas.') then output; /* ignore not ".sas" files */
else
do;
put "WARNING: Only *.sas files are supported." /
"WARNING- The file: " file "will be ignored." /
"WARNING- ";
end;
end;
else
do;
file = "additionalcontent";
fileshort = file;
additionalContent+1;
if additionalContent > 1 then
do;
put "WARNING: Only ONE directory with additional content is allowed!" /
"WARNING- Store all additional content in a single directory." /
"WARNING- The directory: " folder "will be ignored." /
"WARNING- ";
end;
else
do;
/*output;*/
put "NOTE: Additional content located in " folder;
call symputX('additionalContent', folder, "L");
end;
end;
end;
ignoreFolder: ;
rc = dclose(fileId);
@@ -680,6 +714,83 @@ data _null_;
end;
run;
/*======== test for duplicated names of the same type ========*/
proc sort
data = &filesWithCodes.
out = &filesWithCodes._DUPSCHECK
;
by type file order;
run;
data _null_;
set &filesWithCodes._DUPSCHECK;
by type file;
if first.file NE last.file then
do;
if 0 = warnPrinted then
do;
put "WARNING: The following names are duplicated:";
warnPrinted+1;
end;
put "WARNING- " type= file= folder=;
end;
run;
proc delete data = &filesWithCodes._DUPSCHECK;
run;
/*=============================================================*/
%if %superq(additionalContent) NE %then
%do;
/* code inspired by Kurt Bremser's "Talking to Your Host" article */
/* https://communities.sas.com/t5/SAS-User-Groups-Library/WUSS-Presentation-Talking-to-Your-Host/ta-p/838344 */
/* WUSS 2022 */
data &filesWithCodes.addCnt;
run;
data &filesWithCodes.addCnt;
length root dname $ 8192 filename $ 256 dir level 8;
root = "&filesLocation./&additionalContent.";
retain filename dname ' ' level 0 dir 1;
label
filename = "file"
dname = "folder"
;
run;
data &filesWithCodes.addCnt;
modify &filesWithCodes.addCnt;
rc1=filename('tmp',catx('/',root,dname,filename));
rc2=dopen('tmp');
dir = 1 & rc2;
if dir then
do;
dname=catx('/',dname,filename);
filename=' ';
end;
replace;
if dir;
level=level+1;
do i=1 to dnum(rc2);
filename=dread(rc2,i);
output;
end;
rc3=dclose(rc2);
run;
proc sort data=&filesWithCodes.addCnt(where=(filename is not null));
by root dname filename;
run;
%end;
/*
proc contents data = &filesWithCodes.;
run;
@@ -699,9 +810,31 @@ title6 "MD5 hashed fileref of package lowcase name: &_PackageFileref_.";
%end;
proc print data = &filesWithCodes.(drop=base folderRef fileRef rc folderid _abort_ fileId);
proc print data = &filesWithCodes.(drop=base folderRef fileRef rc folderid _abort_ fileId additionalContent);
run;
title;
%if %superq(additionalContent) NE %then
%do;
data _null_;
if not nobs then
do;
put "WARNING: Directory with additional content is empty.";
put "WARNING- Additional content will not be generated.";
call symputX("additionalContent", "", "L");
end;
stop;
set &filesWithCodes.addCnt nobs=nobs;
run;
title2 "Package additional content:";
proc print
data=&filesWithCodes.addCnt(drop=root dir level)
label
;
run;
%end;
title;
options &notesSourceOptions.;
@@ -831,7 +964,8 @@ data _null_;
put ' , options = %str(LOWCASE_MEMNAME) /* possible options for ZIP */ ';
put ' , zip = zip /* file ext. */ ';
put ' , requiredVersion = . /* required version */ ';
put ' , source2 = /* source2*/ ';
put ' , source2 = /* source2 */ ';
put ' , suppressExec = 0 /* suppress execs */ ';
put ' )/secure; ';
put ' %PUT ** NOTE: Package ' "&packageName." ' loaded in ICE mode **; ';
put ' %local _PackageFileref_; ';
@@ -875,6 +1009,9 @@ data _null_;
put ' %local tempLoad_minoperator; ';
put ' %let tempLoad_minoperator = %sysfunc(getoption(minoperator)); ';
put ' options minoperator; ';
put ' %if %superq(suppressExec) NE 1 %then %let suppressExec = 0; ';
put ' %include &_PackageFileref_.(load.sas) / &source2.; ';
put ' options &tempLoad_minoperator.; ';
@@ -1146,7 +1283,7 @@ data _null_;
set &filesWithCodes. end = EOF nobs=NOBS;
by TYPE notsorted;
if (upcase(type) in: ('CLEAN' 'LAZYDATA' 'TEST' 'CASLUDF'))
if (upcase(type) in: ('CLEAN' 'LAZYDATA' 'TEST' 'CASLUDF' 'ADDCNT'))
then continue; /* CASLUDF type will go in the next loop */
/* cleaning files are only included in unload.sas */
/* lazy data are only loaded on demand
@@ -1158,7 +1295,7 @@ data _null_;
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA'
'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/
'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN'
'LAZYDATA' 'TEST'))
'LAZYDATA' 'TEST' 'ADDCNT'))
then
do;
putlog 'WARNING: Type ' type 'is not yet supported.';
@@ -1175,7 +1312,7 @@ data _null_;
do;
/* macro variable for test if cherry picking used FCMP */
put 'data _null_; ';
put ' call symputX("cherryPick_FCMP", 0, "L"); ';
put " call symputX('cherryPick_FCMP', exist('work.%lowcase(&packageName.fcmp)'), 'L'); ";
put 'run; ';
end;
if 1 = FIRST.type and upcase(type)='FUNCTIONS' then
@@ -1187,19 +1324,24 @@ data _null_;
do;
/* macro variable for test if cherry picking used PROTO */
put 'data _null_; ';
put ' call symputX("cherryPick_PROTO", 0, "L"); ';
put " call symputX('cherryPick_PROTO', exist('work.%lowcase(&packageName.proto)'), 'L'); ";
put 'run; ';
end;
if 1 = FIRST.type and upcase(type)='PROTO' then
do;
protoGrpNum+1; /* number of proto directory to create "packageXX" subgroup to prevent overwrite in case
of multiple proc proto dirs because multiple proc proto executed with the same
value of "package=" overwrites previously created content
*/
/* header for multiple functions in one PROTO run */
put "proc proto package = work.%lowcase(&packageName.proto).package ; ";
put "proc proto package = work.%lowcase(&packageName.proto).package" ProtoGrpNum /
" LABEL='Proc Proto C functions for &packageName. package, part" ProtoGrpNum "' ; ";
end;
if 1 = isFormat and upcase(type)=:'FORMAT' then
do;
/* macro variable for test if cherry picking used FORMAT */
put 'data _null_; ';
put ' call symputX("cherryPick_FORMAT", 0, "L"); ';
put " call symputX('cherryPick_FORMAT', cexist('work.%lowcase(&packageName.format)'), 'L'); ";
put 'run; ';
end;
if 1 = FIRST.type and upcase(type)='FORMATS' then
@@ -1235,22 +1377,33 @@ data _null_;
"exist. It will be overwritten by the macro from the &packageName. package, ));";
if upcase(type)=:'EXEC' then
do;
put ' %put NOTE- ;';
put ' %put NOTE- Executing the following code: ;';
put ' %put NOTE- *****************************;';
put ' data _null_;';
put " infile &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') lrecl=32767;';
put ' input;';
put ' putlog "*> " _infile_;';
put ' run;';
put ' %put NOTE- *****************************;';
put ' %put NOTE- ;';
end;
/* include the file with the code of the element */
put ' %include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;';
do;
/* User can suppress running the exec files */
put ' %sysfunc(ifc(1 = %superq(suppressExec)'
/ ' ,%nrstr(%%put INFO: Inclusion of EXEC files is suppressed!;)'
/ ' ,%str('
/ ' data _null_;'
/ ' if _N_=1 then'
/ ' put "NOTE- " /'
/ ' "NOTE- Executing the following code:" /'
/ ' "NOTE- *****************************" / ;'
/ " infile &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') lrecl=32767 end=EOF;'
/ ' input;'
/ ' putlog "*> " _infile_;'
/ ' if EOF=1 then'
/ ' put "NOTE- *****************************" /'
/ ' "NOTE- " / ;'
/ ' run;'
/ ' %include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;'
/ ' )));'
;
end;
else
do;
/* include the file with the code of the element */
put ' %include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;';
end;
if upcase(type)=:'IMLMODULE' then
put ' %let cherryPick_IML = %eval(&cherryPick_IML. + 1);';
@@ -1283,23 +1436,48 @@ data _null_;
/* FOOTERS for IML, FCMP, and PROTO - end */
/* add the link to the functions dataset, only for the first occurrence */
if 1 = isFunction and (upcase(type)=:'FUNCTION') then
/*if 1 = isFunction and (upcase(type)=:'FUNCTION') then
do;
put "options APPEND=(cmplib = work.%lowcase(&packageName.fcmp));"/;
end;*/
if 1 = FIRST.type and (upcase(type)=:'FUNCTION') then
do;
put '%sysfunc(ifc(0<' /
' %sysfunc(findw((%sysfunc(getoption(cmplib)))' /
" ,work.%lowcase(&packageName.fcmp),""'( )'"",RIO))" /
',,%str(options' " APPEND=(cmplib = work.%lowcase(&packageName.fcmp));)" /
'))' ;
end;
/* add the link to the proto functions dataset, only for the first occurrence */
if 1 = isProto and (upcase(type)=:'PROTO') then
/*if 1 = isProto and (upcase(type)=:'PROTO') then
do;
put "options APPEND=(cmplib = work.%lowcase(&packageName.proto));"/;
end;*/
if 1 = FIRST.type and (upcase(type)=:'PROTO') then
do;
put '%sysfunc(ifc(0<' /
' %sysfunc(findw((%sysfunc(getoption(cmplib)))' /
" ,work.%lowcase(&packageName.proto),""'( )'"",RIO))" /
',,%str(options' " APPEND=(cmplib = work.%lowcase(&packageName.proto));)" /
'))' ;
end;
/* add the link to the formats catalog, only for the first occurrence */
if 1 = isFormat and (upcase(type)=:'FORMAT') then
/*if 1 = isFormat and (upcase(type)=:'FORMAT') then
do;
put "options INSERT=(fmtsearch = work.%lowcase(&packageName.format));"/;
end;*/
if 1 = FIRST.type and (upcase(type)=:'FORMAT') then
do;
put '%sysfunc(ifc(0<' /
' %sysfunc(findw((%sysfunc(getoption(fmtsearch)))' /
" ,work.%lowcase(&packageName.format),""'( )'"",RIO))" /
',,%str(options' " INSERT=(fmtsearch = work.%lowcase(&packageName.format));)" /
'))' ;
end;
end; /* loopOverTypes - start */
/* this is a header for CASLudf macro */
@@ -1333,7 +1511,7 @@ data _null_;
' !! '' %put %str( )when set to the value of `HELP` (upcase letters!) displays this help message.;''' /
' !! '' %put - `depList` [technical] contains the list of dependencies required by the package.;''' /
' !! '' %put %str( )for _this_ instance of the macro the default value is: `';
' !! '' %put %str( )for _this_ instance of the macro the default value is: `' @;
%if %superq(packageReqPackages) ne %then
%do;
do i = 1 to countw(packageReqPackages, ",", "Q");
@@ -1343,7 +1521,7 @@ data _null_;
%end;
put +(-1) '`.;''' /
' !! '' %put The macro generated: '' !! put(dtCASLudf, E8601DT19.-L) !! ";"' /
' !! '' %put with the SAS Packages Framework version 20230112.;''' /
' !! '' %put with the SAS Packages Framework version 20230904.;''' /
' !! '' %put ****************************************************************************;''' /
' !! '' %GOTO theEndOfTheMacro;''' /
' !! '' %end;''' ;
@@ -1476,9 +1654,9 @@ data _null_;
put '%if (%str(*)=%superq(cherryPick)) or 0 < &cherryPick_IML_ALL. %then %do;';
/* this "text wrapper" was added to get datetime generated when macro is compiled */
put "data _null_; dtIML=datetime(); IML='"; /* wrapper start */
put "data _null_; dtIML=datetime(); IML="; /* wrapper start */
put '%macro ' " &packageName.IML(list=1,err=ERROR,resetIMLstorage=1,depList=" ;
put '''%macro ' " &packageName.IML(list=1,err=ERROR,resetIMLstorage=1,depList=" ;
%if %superq(packageReqPackages) ne %then
%do;
length reqPackage $ 32;
@@ -1488,25 +1666,25 @@ data _null_;
end;
put ;
%end;
put ")/ des = ""IML Modules loader for &packageName. package""; " /
' %if HELP = %superq(list) %then ' /
' %do; ' /
' %put ****************************************************************************; ' /
' %put This is help for the `' "&packageName.IML" '` macro; ' /
' %put Parameters (optional) are the following:; ' /
put "' !! ')/ des = ""IML Modules loader for &packageName. package""; ' !!" /
''' %if HELP = %superq(list) %then '' !!' /
''' %do; '' !!' /
''' %put ****************************************************************************; '' !!' /
''' %put This is help for the `' "&packageName.IML" '` macro; '' !!' /
''' %put Parameters (optional) are the following:; '' !!' /
' %put - `list` indicates if the list of loaded moduls should be displayed,; ' /
' %put %str( )when set to the value of `1` (the default) runs `SHOW MODULES%str(;)`,; ' /
' %put %str( )when set to the value of `HELP` (upcase letters!) displays this help message.;' /
''' %put - `list` indicates if the list of loaded moduls should be displayed,; '' !!' /
''' %put %str( )when set to the value of `1` (the default) runs `SHOW MODULES%str(;)`,; '' !!' /
''' %put %str( )when set to the value of `HELP` (upcase letters!) displays this help message.;'' !!' /
' %put - `resetIMLstorage` indicates if to reset default moduls storage,; ' /
' %put %str( )when set to `1` (the default) runs `RESET STORAGE = WORK.IMLSTOR%str(;)`.; ' /
''' %put - `resetIMLstorage` indicates if to reset default moduls storage,; '' !!' /
''' %put %str( )when set to `1` (the default) runs `RESET STORAGE = WORK.IMLSTOR%str(;)`.; '' !!' /
' %put - `err` [technical] indicates message type in case of missing modules catalog,; ' /
' %put %str( )when set to the value of `ERROR` (the default) prints Error message.; ' /
''' %put - `err` [technical] indicates message type in case of missing modules catalog,; '' !!' /
''' %put %str( )when set to the value of `ERROR` (the default) prints Error message.; '' !!' /
' %put - `depList` [technical] contains the list of dependencies required by the package.; ' /
' %put %str( )for _this_ instance of the macro the default value is: `';
''' %put - `depList` [technical] contains the list of dependencies required by the package.; '' !!' /
''' %put %str( )for _this_ instance of the macro the default value is: `' @;
%if %superq(packageReqPackages) ne %then
%do;
do i = 1 to countw(packageReqPackages, ",", "Q");
@@ -1514,50 +1692,50 @@ data _null_;
put reqPackage @;
end;
%end;
put +(-1) '`.;' /
' %put The macro generated: ''' " !! put(dtIML, E8601DT19.-L) !! " '''; ' /
' %put with the SAS Packages Framework version 20230112.; ' /
' %put ****************************************************************************; ' /
' %GOTO theEndOfTheMacro; ' /
' %end; ' /
put +(-1) '`.; '' !!' /
''' %put The macro generated: ''' " !! put(dtIML, E8601DT19.-L) !! " '''; '' !!' /
''' %put with the SAS Packages Framework version 20230904.; '' !! ' /
''' %put ****************************************************************************; '' !! ' /
''' %GOTO theEndOfTheMacro; '' !! ' /
''' %end; '' !! ' /
' %local localSYSmacroName localPackageName i depListNm; ' /
' %let localSYSmacroName = &sysmacroname.; ' /
' %let localSYSmacroName = %LOWCASE(&localSYSmacroName.); ' /
' %let localPackageName = %substr(&localSYSmacroName.,1,%eval(%length(&localSYSmacroName.)-3));' /
' ' /
' %if %superq(depList) ne %then ' /
' %do; ' /
' %do i = 1 %to %sysfunc(countw(&depList.,%str( ))); ' /
' %let depListNm = %scan(&depList.,&i.,%str( )); ' /
' %if %SYSMACEXIST(&depListNm.IML) %then ' /
' %do; ' /
' %&depListNm.IML(list=0,err=&err.,resetIMLstorage=0) ' /
' %end; ' /
' %end; ' /
' %end; ' /
' %if %sysfunc(CEXIST(WORK.&localSYSmacroName.)) %then ' /
' %do; ' /
' %put NOTE: Loading IML Modules from package &localPackageName.; ' /
' RESET STORAGE = WORK.&localSYSmacroName.; ' /
' LOAD MODULE = _all_; ' /
' %end; ' /
' %else ' /
' %do; ' /
' %put %superq(err): IML Modules not provided; ' /
' %let list = 0; ' /
' %end; ' /
' %if 1 = %superq(list) %then ' /
' %do; ' /
' SHOW MODULES; ' /
' %end; ' /
' %if 1 = %superq(resetIMLstorage) %then ' /
' %do; ' /
' RESET STORAGE = WORK.IMLSTOR; ' /
' %end; ' /
'%theEndOfTheMacro: %mend; ' ;
''' %local localSYSmacroName localPackageName i depListNm; '' !! ' /
''' %let localSYSmacroName = &sysmacroname.; '' !! ' /
''' %let localSYSmacroName = %LOWCASE(&localSYSmacroName.); '' !! ' /
''' %let localPackageName = %substr(&localSYSmacroName.,1,%eval(%length(&localSYSmacroName.)-3));'' !!' /
put "'; rc = resolve(IML); run;"; /* wrapper end */
''' %if %superq(depList) ne %then '' !!' /
''' %do; '' !!' /
''' %do i = 1 %to %sysfunc(countw(&depList.,%str( ))); '' !!' /
''' %let depListNm = %scan(&depList.,&i.,%str( )); '' !!' /
''' %if %SYSMACEXIST(&depListNm.IML) %then '' !!' /
''' %do; '' !!' /
''' %&depListNm.IML(list=0,err=&err.,resetIMLstorage=0) '' !!' /
''' %end; '' !!' /
''' %end; '' !!' /
''' %end; '' !!' /
''' %if %sysfunc(CEXIST(WORK.&localSYSmacroName.)) %then '' !!' /
''' %do; '' !!' /
''' %put NOTE: Loading IML Modules from package &localPackageName.; '' !!' /
''' RESET STORAGE = WORK.&localSYSmacroName.; '' !!' /
''' LOAD MODULE = _all_; '' !!' /
''' %end; '' !!' /
''' %else '' !!' /
''' %do; '' !!' /
''' %put %superq(err): IML Modules not provided; '' !!' /
''' %let list = 0; '' !!' /
''' %end; '' !!' /
''' %if 1 = %superq(list) %then '' !!' /
''' %do; '' !!' /
''' SHOW MODULES; '' !!' /
''' %end; '' !!' /
''' %if 1 = %superq(resetIMLstorage) %then '' !!' /
''' %do; '' !!' /
''' RESET STORAGE = WORK.IMLSTOR; '' !!' /
''' %end; '' !!' /
'''%theEndOfTheMacro: %mend; '' ' ;
put "; rc = resolve(IML); run;"; /* wrapper end */
put '%put NOTE: Macro named:; ';
put '%put %nrstr( %%)' "&packageName." 'IML(); ';
@@ -2036,7 +2214,7 @@ data _null_;
put " stop; ";
put "run; ";
/* cleanup */
/* clean-up */
put "proc delete data = WORK._last_; ";
put "run; ";
put 'options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.; ' /;
@@ -2124,7 +2302,15 @@ data _null_;
put ' end ; ';
%end;
put 'put "***"; put "* SAS package generated by generatePackage, version 20230112 *"; put "***";';
%if %superq(additionalContent) NE %then
%do;
put 'put ;' / 'put @3 ''Package contains additional content, run: %loadPackageAddCnt(' "&packageName." ') to load it'';';
put "put @3 'or look for the %lowcase(&packageName.)_AdditionalContent directory in the Packages fileref';";
put "put @3 'localization (only if additional content was deployed during the installation process).';" / "put ;";
%end;
put 'put "***"; put "* SAS package generated by generatePackage, version 20230904 *"; put "***";';
put 'run; ' /;
@@ -2218,15 +2404,37 @@ data _null_;
put " stop; ";
put "run; ";
/* cleanup */
/* clean up */
put "proc delete data = WORK._last_; ";
put "run; ";
put 'options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.; ' /;
/* generate dataset witch content information */
put 'data &packageContentDS. _NULL_; '
/ ' if "&packageContentDS." = " " then stop; '
/ ' infile cards4 dlm = "/"; '
/ ' input (folder order type file fileshort) (: $ 256.); '
/ ' output; '
/ 'cards4; '
;
EOFDS = 0;
do until(EOFDS);
/* content is created during package creation */
set &filesWithCodes. end = EOFDS;
if upcase(type) in: ('TEST') then continue; /* exclude tests */
strX = catx('/', folder, order, type, file, fileshort);
put strX;
end;
put ";;;;"
/ "run;"
/ 'options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.; '
/ ;
put '%put NOTE: '"Help for package &packageName., version &packageVersion., license &packageLicense.;";
put '%put NOTE- *** END ***;' /;
put "/* help.sas end */";
stop;
run;
@@ -2247,7 +2455,7 @@ data _null_;
if NOBS = 0 then stop;
set &filesWithCodes. nobs = NOBS end = EOF;
if (upcase(type) not in: ('TEST')); /* test files are not to be copied */
if (upcase(type) not in: ('TEST' 'ADDCNT')); /* test files and additional content are not to be copied */
call execute(cat ('filename _SPFIN_ "', catx('/', base, folder, file), '";'));
call execute(cats("filename _SPFOUT_ ZIP '", base, "/%lowcase(&packageName.).zip' member='_", folder, ".", file, "';") );
@@ -2322,6 +2530,104 @@ data _null_;
end;
run;
/* Additional Content */
/* check if a file with additional content exists in the Work library */
filename _SPFOUT_ "%sysfunc(pathname(work,L))/addcnt.zip";
%if %sysfunc(fexist(_SPFOUT_)) %then
%do;
%if %sysfunc(fdelete(_SPFOUT_)) NE 0 %then
%do;
%put ERROR: Additional content for package not generated!;
%put ERROR- Delete "%sysfunc(pathname(work,L))/addcnt.zip" file;
%put ERROR- and try again.;
%let additionalContent=;
%end;
%end;
filename _SPFOUT_ clear;
%if %superq(additionalContent) NE %then
%do;
%put ;
%put Status of additional content for the package:;
/* create "addcnt.zip" file for Additional Content */
data _null_;
set &filesWithCodes.addCnt;
if dir=0;
rc1=filename("_SPFIN_" , catx('/',root,dname,filename), "disk", "lrecl=1 recfm=n");
length rc1txt $ 8192;
rc1txt=sysmsg();
rc2=filename("_SPFOUT_", "%sysfunc(pathname(work,L))/addcnt.zip", "ZIP"
,"lrecl=1 recfm=n member='" !! catx('/',dname,filename) !! "'");
length rc2txt $ 8192;
rc2txt=sysmsg();
do _N_ = 1 to 10;
rc3=fcopy("_SPFIN_","_SPFOUT_");
length rc3txt $ 8192;
rc3txt=sysmsg();
if fexist("_SPFOUT_") then leave;
else sleeprc=sleep(0.25,1);
end;
rc4=fexist("_SPFOUT_");
length rc4txt $ 8192;
rc4txt=sysmsg();
if rc4 = 0 then
do;
call symputX("createPackageContentStatus",1,"L");
put "ERROR:" @;
end;
put "AddCnt: " dname +(-1) "/" filename /
"Try=" _N_ "Return codes:" /
(rc:) (=);
rc1=filename("_SPFIN_");
rc2=filename("_SPFOUT_");
run;
/* inserting addcnt.zip into the package file */
%put ;
%put Status of inserting "addcnt.zip" into the package file:;
data _null_;
rc1=filename("_SPFIN_" , "%sysfunc(pathname(work,L))/addcnt.zip", "disk", "lrecl=1 recfm=n");
length rc1txt $ 8192;
rc1txt=sysmsg();
rc2=filename("_SPFOUT_", pathname("&zipReferrence.","F"), "ZIP", "lrecl=1 recfm=n member='addcnt.zip'");
length rc2txt $ 8192;
rc2txt=sysmsg();
do _N_ = 1 to 10;
rc3=fcopy("_SPFIN_","_SPFOUT_");
length rc3txt $ 8192;
rc3txt=sysmsg();
if fexist("_SPFOUT_") then leave;
else sleeprc=sleep(0.25,1);
end;
rc4=fexist("_SPFOUT_");
length rc4txt $ 8192;
rc4txt=sysmsg();
if rc4 then
rc5=fdelete("_SPFIN_");
else
do;
call symputX("createPackageContentStatus",1,"L");
put "ERROR:" @;
end;
put "File addcnt.zip, Try=" _N_ "Return codes:" /
(rc:) (=);
rc1=filename("_SPFIN_");
rc2=filename("_SPFOUT_");
run;
%end;
options notes source;
%put NOTE-;
%put NOTE-######################################################;
@@ -2444,6 +2750,10 @@ run;
put @n '%unloadPackage'"(&packageName.,";
put @n " path=&filesLocation.) " /;
/* additional content */
put @n '%loadPackageAddCnt'"(&packageName.,";
put @n " path=&filesLocation.) " /;
put ;
put '***************************************************';
run;
@@ -2661,6 +2971,10 @@ data _null_;
put '%unloadPackage'"(&packageName.,";
put " path=&filesLocation.) " /;
/* additional content */
put '%loadPackageAddCnt'"(&packageName.,";
put " path=&filesLocation.) " /;
put "filename packages '&filesLocation.';" /
'%listPackages() ' /;
@@ -2909,6 +3223,11 @@ options &quotelenmax_tmp.;
proc sql;
drop table &filesWithCodes.;
%if %sysfunc(exist(&filesWithCodes.addCnt)) %then
%do;
drop table &filesWithCodes.addCnt;
%end;
quit;
/* turn on the original value of the note about quoted string length */

View File

@@ -20,11 +20,15 @@
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use helpPackage in the form:
%helpPackage(PiPackage, *, zip=disk, options=)
*/
%helpPackage(PiPackage, *, zip=disk, options=) */
, packageContentDS = 0 /* indicates if a data set with package
content should be generated in WORK,
if set to 1 then WORK.packageName_content
dataset is created
*/
)/secure
/*** HELP END ***/
des = 'Macro to get help about SAS package, version 20230112. Run %helpPackage() for help info.'
des = 'Macro to get help about SAS package, version 20230904. Run %helpPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
@@ -39,7 +43,7 @@ des = 'Macro to get help about SAS package, version 20230112. Run %helpPackage()
%put ### This is short help information for the `helpPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to get help about SAS packages, version `20230112` #;
%put # Macro to get help about SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -80,6 +84,11 @@ des = 'Macro to get help about SAS package, version 20230112. Run %helpPackage()
%put # and use helpPackage in the following form: #;
%put # `%nrstr(%%helpPackage(PiPackage, ,zip=disk, options=))` #;
%put # #;
%put # - `packageContentDS=` *Optional.* Indicates if a data set with package #;
%put # content should be generated in `WORK`, #;
%put # with default value (`0`) the dataset is not produced, #;
%put # if set to `1` then `WORK.packageName_content`. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
@@ -153,6 +162,9 @@ des = 'Macro to get help about SAS package, version 20230112. Run %helpPackage()
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%if 1=%superq(packageContentDS) %then %let packageContentDS=work.&packageName._content;
%else %let packageContentDS=;
%include &_PackageFileref_.(help.sas) / &source2.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
@@ -169,7 +181,7 @@ TODO:
- add MD5(&packageName.) value hash instead "package" word in filenames [DONE]
*/
/* Macros to install SAS packages, version 20230112 */
/* Macros to install SAS packages, version 20230904 */
/* A SAS package is a zip file containing a group of files
with SAS code (macros, functions, data steps generating
data, etc.) wrapped up together and %INCLUDEed by

View File

@@ -10,11 +10,13 @@
, URLuser = /* user name for the password protected URLs */
, URLpass = /* password for the password protected URLs */
, URLoptions = /* options for the `sourcePath` URLs */
, loadAddCnt=0 /* should the additional content be loaded?
default is 0 - means No, 1 means Yes */
)
/secure
minoperator
/*** HELP END ***/
des = 'Macro to install SAS package, version 20230112. Run %%installPackage() for help info.'
des = 'Macro to install SAS package, version 20230904. Run %%installPackage() for help info.'
;
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
%do;
@@ -29,7 +31,7 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
%put ### This is short help information for the `installPackage` macro #;
%put #--------------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to install SAS packages, version `20230112` #;
%put # Macro to install SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -86,6 +88,13 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
%put # - `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS #;
%put # documentation for the further details. #;
%put # #;
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
%put # content. The option indicates if it should be loaded #;
%put # Default value of zero (`0`) means "No", one (`1`) #;
%put # means "Yes". Content is extracted into the **packages** fileref #;
%put # directory in `<packageName>_AdditionalContent` folder. #;
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
%put # #;
%put #--------------------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
@@ -286,6 +295,8 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
filename out list;
*/
/* copy the file byte-by-byte */
%local installationRC;
%let installationRC=1;
data _null_;
length filein 8 out_path in_path $ 4096;
out_path = pathname ("&out");
@@ -323,7 +334,7 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
if symgetn("replace")=1 then
do;
put @2 "The following file will be replaced during "
/ @2 "instalation of the &packageName. package: "
/ @2 "installation of the &packageName. package: "
/ @5 out_path;
rc = FDELETE("&out");
rc = FCOPY("&in", "&out");
@@ -337,10 +348,24 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
end;
put @2 "Done with return code " rc= "(zero = success)";
call symputX("installationRC", rc, "L");
run;
filename &in clear;
filename &out clear;
%if 1 = &loadAddCnt.
AND 0 = &installationRC.
AND NOT (%upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK))
%then
%do;
%put; %put - Additional content loading - Start -;
%loadPackageAddCnt(&packageName.
,path=&firstPackagesPath.
,target=&firstPackagesPath.
)
%put - Additional content loading - End -;
%end;
%put *** %lowcase(&packageName.) end *******************************************;
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
%end;
@@ -458,7 +483,7 @@ des = 'Macro to install SAS package, version 20230112. Run %%installPackage() fo
/* Macro to list SAS packages in packages folder.
Version 20230112
Version 20230904
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating

View File

@@ -1,7 +1,7 @@
/*+listPackages+*/
%macro listPackages()/secure PARMBUFF
des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HELP) for help, version 20230112.'
des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HELP) for help, version 20230904.'
;
%if %QUPCASE(&SYSPBUFF.) = %str(%(HELP%)) %then
%do;
@@ -16,7 +16,7 @@ des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HE
%put ### This is short help information for the `listPackages` macro #;
%put #-----------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to list available SAS packages, version `20230112` #;
%put # Macro to list available SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -166,7 +166,7 @@ options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
/* Macro to generate SAS packages.
Version 20230112
Version 20230904
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating

View File

@@ -23,15 +23,18 @@
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use loadPackage in the form:
%loadPackage(PiPackage, zip=disk, options=)
*/
%loadPackage(PiPackage, zip=disk, options=) */
, cherryPick=* /* space separated list of selected elements of the package
to be loaded into the session, default value "*" means
"load all elements of the package"
"load all elements of the package" */
, loadAddCnt=0 /* should the additional content be loaded?
default is 0 - means No, 1 means Yes */
, suppressExec=0 /* indicates if loading of exec files
should be suppressed, 1=suppress
*/
)/secure
/*** HELP END ***/
des = 'Macro to load SAS package, version 20230112. Run %loadPackage() for help info.'
des = 'Macro to load SAS package, version 20230904. Run %loadPackage() for help info.'
minoperator
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
@@ -47,7 +50,7 @@ minoperator
%put ### This is short help information for the `loadPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to *load* SAS packages, version `20230112` #;
%put # Macro to *load* SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
@@ -96,6 +99,17 @@ minoperator
%put # Default value of an asterisk (*) means: #;
%put # "load all elements of the package". #;
%put # #;
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
%put # content. The option indicates if it should be loaded #;
%put # Default value of zero (`0`) means "No", one (`1`) #;
%put # means "Yes". Content is extracted into the **Work** #;
%put # directory in `<packageName>_AdditionalContent` folder. #;
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
%put # #;
%put # - `suppressExec=` *Optional.* Indicates if loading of `exec` type files #;
%put # should be suppressed, default value is `0`, #;
%put # when set to `1` `exec` files are *not* loaded #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
@@ -187,6 +201,16 @@ minoperator
%let cherryPick=*;
%end;
%if %superq(loadAddCnt) NE 1 %then
%do;
%let loadAddCnt = 0;
%end;
%if %superq(suppressExec) NE 1 %then
%do;
%let suppressExec = 0;
%end;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
@@ -224,13 +248,20 @@ minoperator
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%if %bquote(&lazyData.) = %then
%if %superq(lazyData) = %then
%do;
%local tempLoad_minoperator;
%let tempLoad_minoperator = %sysfunc(getoption(minoperator));
options minoperator; /* MinOperator option is required for cherryPicking to work */
%include &_PackageFileref_.(load.sas) / &source2.;
options &tempLoad_minoperator.;
%if 1 = &loadAddCnt. %then
%do;
%put; %put - Additional content loading - Start -;
%loadPackageAddCnt(&packageName.,
path=&path.)
%put - Additional content loading - End -;
%end;
%end;
%else
%do;

View File

@@ -0,0 +1,375 @@
/*+loadPackageAddCnt+*/
/*** HELP START ***/
%macro loadPackageAddCnt(
packageName /* name of a package,
e.g. myPackage,
required and not null */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, target = %sysfunc(pathname(WORK)) /* a path in which the directory with
additional content will be generated,
name of directory created is set to
`&packageName._AdditionalContent`
default location is SAS work */
, source2 = /*source2*/ /* option to print out details,
null by default */
, requiredVersion = . /* option to test if loaded package
is provided in required version */
)/secure
/*** HELP END ***/
des = 'Macro to load additional content for a SAS package, version 20230904. Run %loadPackageAddCnt() for help info.'
minoperator
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `loadPackageAddCnt` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to *load* additional content for a SAS package, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and included by #;
%put # a single `load.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%loadPackageAddCnt())` macro loads additional content #;
%put # for a package (of course only if one is provided). #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%loadPackageAddCnt(myPackage))`. #;
%put # If empty displays this help information. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `target=` *Optional.* Location where the directory with #;
%put # additional content will be generated, #;
%put # name of the directory created is set to #;
%put # `<packagename>_AdditionalContent`, the default #;
%put # location is `%nrstr(%%sysfunc(pathname(WORK)))` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
%put # package is provided in required version, #;
%put # default value: `.` #;
%put # #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put ### Example 1 ###################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading additional content #;
%put # for the SQLinDS package. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%loadPackageAddCnt(SQLinDS) %%* load additional content for the package; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put # #;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofloadPackageAddCnt;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp zip;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let stimer_tmp = %sysfunc(getoption(stimer));
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
%let zip = zip;
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_;
call symputX("_PackageFileref_", "A" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
call symputX("_TargetFileref_", "T" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip."
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
filename &_PackageFileref_. &ZIP.
/* check existence of addcnt.zip inside package */
"&path./%lowcase(&packageName.).&zip."
member='addcnt.zip'
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
/* get metadata */
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip."
;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
/* test if required version of package is "good enough" */
%local rV pV;
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
+ (%scan(&pV.,2,.,M)+0)*1e4
+ (%scan(&pV.,3,.,M)+0)*1e0);
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
+ (%scan(&rV.,2,.,M)+0)*1e4
+ (%scan(&rV.,3,.,M)+0)*1e0);
%if %sysevalf(&rV. > &pV.) %then
%do;
%put ERROR: Additional content for package &packageName. will not be loaded!;
%put ERROR- Required version is &requiredVersion.;
%put ERROR- Provided version is &packageVersion.;
%put ERROR- Verify installed version of the package.;
%put ERROR- ;
%GOTO WrongVersionOFPackageAddCnt; /*%RETURN;*/
%end;
/*options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;*/
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip."
member='addcnt.zip'
;
/*********************/
filename &_TargetFileref_. "&target.";
%if %sysfunc(fexist(&_TargetFileref_.)) %then
%do;
%if %sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent)) %then
%do; /* dir for AC already exists */
%put WARNING: Target location:;
%put WARNING- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
%put WARNING- already exist. Please remove it manually to upload additional contents.;
%put WARNING- Additional Content will not be loaded.;
%put WARNING- ;
%end;
%else
%do;
/*-+-+-+-*/
/* create target location */
%put INFO:;
%put Additional content will be located in:;
%put %sysfunc(dcreate(%lowcase(&packageName.)_AdditionalContent,%sysfunc(pathname(&_TargetFileref_.))));
%if NOT (%sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent))) %then
%do; /* dir for AC cannot be generated */
%put ERROR: Cannot create target location:;
%put ERROR- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
%put ERROR- Additional Content will not be loaded.;
%put ERROR- ;
%end;
%else
%do;
/* extract addcnt.zip to work and, if successful, load additional content */
%put NOTE- **%sysfunc(DoSubL(%nrstr(
;
options nonotes nosource ps=min ls=max;
data _null_;
call symputx("AdditionalContent", 0, "L");
rc1=filename("in", pathname("&_PackageFileref_."), "ZIP", "lrecl=1 recfm=n member='addcnt.zip'");
length rc1txt $ 8192;
rc1txt=sysmsg();
if fexist("in") then
do;
rc2=filename("out", pathname("WORK")!!"/%lowcase(&packageName.)addcnt.zip", "disk", "lrecl=1 recfm=n");
length rc2txt $ 8192;
rc2txt=sysmsg();
rc3=fcopy("in","out");
length rc3txt $ 8192;
rc3txt=sysmsg();
if rc3 then put _N_ @12 (rc:) (=);
if fexist("out") then
do;
call symputx("AdditionalContent", 1, "L");
end;
else put "INFO: No additional content for package &packageName..";
rc1=filename("in");
rc2=filename("out");
end;
else
do;
call symputx("AdditionalContent", 0, "L");
put "INFO: No additional content for package &packageName..";
end;
run;
%if &AdditionalContent. %then
%do;
filename f DUMMY;
filename f ZIP "%sysfunc(pathname(WORK))/%lowcase(&packageName.)addcnt.zip";
options dlCreateDir;
libname outData "%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent";
data WORK.__&_TargetFileref_._zip___;
did = dopen("f");
if not did then
do;
put "ERROR: Can not access Additional Content data.";
stop;
end;
if did then
do i=1 to dnum(did);
length file $ 8192;
file = dread(did, i);
output;
keep file;
end;
did = dclose(did);
run;
data _null_;
set WORK.__&_TargetFileref_._zip___ end = EOF;
wc = countw(file,"/\");
length libText pathname_f $ 8192;
libText = pathname("outData", "L");
if scan(file, wc , "/\") = "" then
do j = 1 to wc-1;
libText = catx("/", libText, scan(file, j , "/\"));
rc = libname("test", libText);
rc = libname("test");
end;
else
do;
do j = 1 to wc-1;
libText = catx("/", libText, scan(file, j , "/\"));
rc = libname("test", libText);
rc = libname("test");
end;
pathname_f = pathname("f");
rc1 = filename("in", strip(pathname_f), "zip", "member='" !! strip(file) !! "' lrecl=1 recfm=n");
length rc1txt $ 8192;
rc1msg = sysmsg();
rc2 = filename("out", catx("/", libText, scan(file, j , "/\")), "disk", "lrecl=1 recfm=n");
length rc2txt $ 8192;
rc2msg = sysmsg();
rc3 = fcopy("in", "out");
length rc3txt $ 8192;
rc3msg = sysmsg();
loadingProblem + (rc3 & 1);
if rc3 then
do;
put "ERROR: Cannot extract: " file;
put (rc1 rc2 rc3) (=);
put (rc1msg rc2msg rc3msg) (/);
put "ERROR-";
end;
crc1=filename("in");
crc2=filename("out");
end;
if EOF and loadingProblem then
do;
put "ERROR: Not all files from Additional Content were extracted successfully!";
end;
run;
data _null_;
rc = fdelete("f");
run;
proc delete data = WORK.__&_TargetFileref_._zip___;
run;
libname outData;
filename f DUMMY;
%end;
)))**;
%end;
/*-+-+-+-*/
%end;
%end;
%else
%do;
%put ERROR: Cannot access target location:;
%put ERROR- %sysfunc(pathname(&_TargetFileref_.));
%put ERROR- Additional Content will not be loaded.;
%put ERROR- ;
%end;
filename &_TargetFileref_. clear;
/*********************/
%end;
%else %put INFO: No additional content for &packageName. package.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
%WrongVersionOFPackageAddCnt:
/* restore optionos */
options ls = &ls_tmp. ps = &ps_tmp.
&notes_tmp. &source_tmp.
&stimer_tmp. &fullstimer_tmp.
msglevel=&msglevel_tmp.;
%ENDofloadPackageAddCnt:
%mend loadPackageAddCnt;
/**/

View File

@@ -11,7 +11,7 @@
*/
)/secure
/*** HELP END ***/
des = 'Macro to load multiple SAS packages at one run, version 20230112. Run %loadPackages() for help info.'
des = 'Macro to load multiple SAS packages at one run, version 20230904. Run %loadPackages() for help info.'
parmbuff
;
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
@@ -27,7 +27,7 @@ parmbuff
%put ### This is short help information for the `loadPackageS` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro wrapper for the loadPackage macro, version `20230112` #;
%put # Macro wrapper for the loadPackage macro, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;

View File

@@ -23,7 +23,7 @@
*/
)/secure
/*** HELP END ***/
des = 'Macro to preview content of a SAS package, version 20230112. Run %previewPackage() for help info.'
des = 'Macro to preview content of a SAS package, version 20230904. Run %previewPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
@@ -38,7 +38,7 @@ des = 'Macro to preview content of a SAS package, version 20230112. Run %preview
%put ### This is short help information for the `previewPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to get previwe of a SAS packages, version `20230112` #;
%put # Macro to get previwe of a SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;

View File

@@ -20,7 +20,7 @@
*/
)/secure
/*** HELP END ***/
des = 'Macro to unload SAS package, version 20230112. Run %unloadPackage() for help info.'
des = 'Macro to unload SAS package, version 20230904. Run %unloadPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
@@ -35,7 +35,7 @@ des = 'Macro to unload SAS package, version 20230112. Run %unloadPackage() for h
%put ### This is short help information for the `unloadPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to unload SAS packages, version `20230112` #;
%put # Macro to unload SAS packages, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;

View File

@@ -13,7 +13,7 @@
hashing_file() function, SAS 9.4M6 */
)/secure
/*** HELP END ***/
des = 'Macro to verify SAS package with the hash digest, version 20230112. Run %verifyPackage() for help info.'
des = 'Macro to verify SAS package with the hash digest, version 20230904. Run %verifyPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
@@ -28,7 +28,7 @@ des = 'Macro to verify SAS package with the hash digest, version 20230112. Run %
%put ### This is short help information for the `verifyPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to verify SAS package with it hash digest, version `20230112` #;
%put # Macro to verify SAS package with it hash digest, version `20230904` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;

View File

@@ -10,6 +10,7 @@
* [the `previewPackage` macro](#previewPackage)
* [the `generatePackage` macro](#generatepackage)
* [the `extendPackagesFileref` macro](#extendpackagesfileref)
* [the `loadPackageAddCnt` macro](#loadpackageaddcnt)
* [Some more examples](#some-more-examples)
---
@@ -21,7 +22,7 @@ A **SAS package** is an automatically generated, single, stand alone *zip* file
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20230112`**.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20230905`**.
**To get started with SAS Packages** try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
@@ -39,7 +40,7 @@ After assigning the directory do not change them when using the SPF since it may
## This is short help information for the `installPackage` macro <a name="installpackage"></a>
--------------------------------------------------------------------------------------------
Macro to install SAS packages, version `20230112`
Macro to install SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -94,6 +95,13 @@ After assigning the directory do not change them when using the SPF since it may
- `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS
documentation for the further details.
- `loadAddCnt=` *Optional.* A package zip may contain additional
content. The option indicates if it should be loaded
Default value of zero (`0`) means "No", one (`1`)
means "Yes". Content is extracted into the **packages** fileref
directory in `<packageName>_AdditionalContent` folder.
For other locations use `%loadPackageAddCnt()` macro.
--------------------------------------------------------------------------------------------
@@ -141,7 +149,7 @@ filename packages "C:/SAS_PACKAGES";
## This is short help information for the `helpPackage` macro <a name="helppackage"></a>
-------------------------------------------------------------------------------
Macro to get help about SAS packages, version `20230112`
Macro to get help about SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -182,6 +190,11 @@ filename packages "C:/SAS_PACKAGES";
and use helpPackage in the following form:
`%helpPackage(PiPackage, , zip=disk, options=)`
- `packageContentDS=` *Optional.* Indicates if a data set with package
content should be generated in `WORK`,
with default value (`0`) the dataset is not produced,
if set to `1` then `WORK.packageName_content`.
-------------------------------------------------------------------------------
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
@@ -212,7 +225,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `loadPackage` macro <a name="loadpackage"></a>
-------------------------------------------------------------------------------
Macro to *load* SAS packages, version `20230112`
Macro to *load* SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -261,6 +274,17 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
Default value of an asterisk (*) means:
"load all elements of the package".
- `loadAddCnt=` *Optional.* A package zip may contain additional
content. The option indicates if it should be loaded
Default value of zero (`0`) means "No", one (`1`)
means "Yes". Content is extracted into the **Work**
directory in `<packageName>_AdditionalContent` folder.
For other locations use `%loadPackageAddCnt()` macro.
- `suppressExec=` *Optional.* Indicates if loading of `exec` type files
should be suppressed, default value is `0`,
when set to `1` `exec` files are *not* loaded
-------------------------------------------------------------------------------
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
@@ -353,7 +377,7 @@ If created, those macros are automatically deleted when the `%unloadPackage()` m
## This is short help information for the `loadPackageS` macro <a name="loadpackages"></a>
-------------------------------------------------------------------------------
Macro wrapper for the loadPackage macro, version `20230112`
Macro wrapper for the loadPackage macro, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -402,7 +426,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `unloadPackage` macro <a name="unloadpackage"></a>
-------------------------------------------------------------------------------
Macro to unload SAS packages, version `20230112`
Macro to unload SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -467,7 +491,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `listPackages` macro <a name="listpackages"></a>
-----------------------------------------------------------------------------------------
Macro to list available SAS packages, version `20230112`
Macro to list available SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -508,7 +532,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `verifyPackage` macro <a name="verifypackage"></a>
-------------------------------------------------------------------------------
Macro to verify SAS package with it hash digest, version `20230112`
Macro to verify SAS package with it hash digest, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -562,7 +586,7 @@ filename packages "C:/SAS_PACKAGES"; %* set-up a directory for packages;
## This is short help information for the `previewPackage` macro <a name="previewpackage"></a>
-------------------------------------------------------------------------------
Macro to get previwe of a SAS packages, version `20230112`
Macro to get previwe of a SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -629,7 +653,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `generatePackage` macro <a name="generatepackage"></a>
-------------------------------------------------------------------------------
Macro to generate SAS packages, version `20230112`
Macro to generate SAS packages, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -799,6 +823,15 @@ All files have to have `.sas` extension. Other files are ignored.
|
+-...
|
+-998_addcnt [additional content for the package, can be only one!, content of this
| | directory is copied "as is"]
| |
| +-arbitrary_file1 [an arbitrary file ]
| |
| +-subdirectory_with_files [an arbitrary directory with some files inside]
| |
| +-...
|
+-999_test [tests executed during package generation, XCMD options must be turned-on]
| |
| +-test1.sas [a file with a code for test1]
@@ -813,7 +846,7 @@ All files have to have `.sas` extension. Other files are ignored.
## This is short help information for the `extendPackagesFileref` macro <a name="extendpackagesfileref"></a>
-----------------------------------------------------------------------------------------
Macro to list directories pointed by 'packages' fileref, version `20230112`
Macro to list directories pointed by 'packages' fileref, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -848,9 +881,98 @@ filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %* setup a directory for packages
filename packages ("D:/NEW_DIR" %extendPackagesFileref()); %* add new directory;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------------------------------------
## This is short help information for the `loadPackageAddCnt` macro <a name="loadpackageaddcnt"></a>
-------------------------------------------------------------------------------
Macro to load *additional content* for a SAS package, version `20230905`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
data, etc.) wrapped up together and included by
a single `load.sas` file (also embedded inside the zip).
The `%loadPackageAddCnt()` macro loads additional content
for a package (of course only if one is provided).
-------------------------------------------------------------------------------
### Parameters:
1. `packageName` *Required.* Name of a package, e.g. myPackage,
Required and not null, default use case:
`%loadPackageAddCnt(myPackage)`.
If empty displays this help information.
- `path=` *Optional.* Location of a package. By default it
looks for location of the **packages** fileref, i.e.
`%sysfunc(pathname(packages))`
- `target=` *Optional.* Location where the directory with
additional content will be generated,
name of the directory created is set to
`<packagename>_AdditionalContent`, the default
location is `%sysfunc(pathname(WORK))`
- `source2=` *Optional.* Option to print out details about
what is loaded, null by default.
- `requiredVersion=` *Optional.* Option to test if the loaded
package is provided in required version,
default value: `.`
-------------------------------------------------------------------------------
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
to learn more.
-------------------------------------------------------------------------------
By *default* additional content is not deployed automatically e.g.,
from security point of view, or production job doesn't need it to run, etc.
But if there is a need for it there are three ways to get it:
- The first one ("by-the-book"), and also the recommended one. The additional
content is extracted during the automatic installation process using the
`\%installPackage()` macro. For this to work the `loadAddCnt=` parameter
has to be set to `1`. The additional content is extracted to the
`<packageName>_AdditionalContent` directory into the same location where
the package is installed i.e., inside `packages` fileref location.
- The second one ("by-the-work"), when the additional content is extracted
during the loading process with the `\%loadPackage()` macro. For this to
work also the `loadAddCnt=` parameter has to be set to `1`. The additional
content is extracted to the `<packageName>_AdditionalContent` directory
inside the `Work` library location.
- The third one ("by-the-user"), when the additional content is extracted
with dedicated `%loadPackageAddCnt()` macro. By default the additional
content is extracted to the `<packageName>_AdditionalContent` directory
inside the `Work` library location too, but it can be altered by changing
the `target=` parameter, which indicates the location.
If done "by-the-book", or "by-the-user" with `target=` parameter, the
additional content is not automatically deleted when SAS session ends,
in this case the "additionals" have to be deleted manually by the User.
### Example 1 ##################################################################
Enabling the SAS Package Framework
from the local directory and installing & loading additional content
for the SQLinDS package.
Assume that the `SPFinit.sas` file
is located in the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%installPackage(SQLinDS) %* install the package from the Internet;
%loadPackageAddCnt(SQLinDS) %* load additional content for the package;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-------------------------------------------------------------------------------
## Some more examples <a name="some-more-examples"></a> #############################################################

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
Copyright (c) 2019 - 2022 Bartosz Jablonski
Copyright (c) 2019 - 2023 Bartosz Jablonski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -10,7 +10,7 @@ Packages:
---
- **SQLinDS**\[2.2.4\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
- **SQLinDS**\[2.2.7\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
```sas
data class;
set %SQL(
@@ -22,13 +22,13 @@ data class;
WH = weight + height;
run;
```
SHA256 digest for SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
SHA256 digest for SQLinDS: F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
---
- **DFA** (Dynamic Function Arrays)\[0.5.4\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
- **DFA** (Dynamic Function Arrays)\[0.5.6\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
```sas
%createDFArray(ArrDynamic, resizefactor=17);
@@ -55,13 +55,13 @@ data _null_;
end;
run;
```
SHA256 digest for DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
SHA256 digest for DFA: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
---
- **macroArray**\[1.0.4\], implementation of an array concept in a macro language, e.g.
- **macroArray**\[1.1.0\], implementation of an array concept in a macro language, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -80,13 +80,13 @@ SHA256 digest for DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A
which = 1:H:2
);
```
SHA256 digest for macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
SHA256 digest for macroArray: F*6A22A01868F4203862B3685F543D723C7DB8E9AB3C1A6357D2BFA030971B0D3C
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
---
- **BasePlus**\[1.18.4\] adds a bunch of functionalities I am missing in BASE SAS, such as:
- **BasePlus**\[1.30.0\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```sas
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
@@ -103,26 +103,32 @@ format x bool.;
%rainCloudPlot(sashelp.cars,DriveTrain,Invoice)
%zipLibrary(sashelp,libOut=work)
%bpPIPE(ls -la ~/)
%dirsAndFiles(C:\SAS_WORK\,ODS=work.result)
%put %repeatTxt(#,15,s=$) HELLO SAS! %repeatTxt(#,15,s=$);
```
SHA256 digest for BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
SHA256 digest for BasePlus: F*B91771D45C781B6806DBB44A3B491A0784D7698B9F3BBBE1A86EE5594834315F
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
---
- **GSM** (Generate Secure Macros)\[0.20.4\], package allows
- **GSM** (Generate Secure Macros)\[0.21.1\], 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: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
SHA256 digest for GSM: F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
---
- **dynMacroArray**\[0.2.4\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
- **dynMacroArray**\[0.2.6\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
SHA256 digest for dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
SHA256 digest for dynMacroArray: F*F50BEDB542D96B07C763EAB7549FBC5F08ED389DC2338BFAAEBFBD1FD20E22B6
---

View File

@@ -1,3 +1,58 @@
/* 20230919 */
BasePlus: F*B91771D45C781B6806DBB44A3B491A0784D7698B9F3BBBE1A86EE5594834315F
/* 20230906 */
macroArray: F*6A22A01868F4203862B3685F543D723C7DB8E9AB3C1A6357D2BFA030971B0D3C
/* 20230904 */
BasePlus: F*2FE68DD9B3692B9D46EF85B82F63C7E65010BF9E89D670FD1779F4670FA03F31
DFA: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62
dynMacroArray: F*F50BEDB542D96B07C763EAB7549FBC5F08ED389DC2338BFAAEBFBD1FD20E22B6
GSM: F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682
macroArray: F*4FAAEE7DF2854EA31933AE017A89C1615C7291A66A07CCE345041EB0D587ED4E
SQLinDS: F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9
/* 20230824 */
BasePlus: F*9EEE4F4B99EA725B60141645AB6A50BFEBA32CE54848593F8D832D907D63CAD7
/* 20230727 */
GSM: F*56DC0DCCE06B4281BF3FA6FA3875CBA87772BDA7FAB601B06740A7980FFB0E07
/* 20230602 */
BasePlus: F*D6DC5AD1B60A92AD300B639B3C361C1F7846EB01E5AB35BF4FDDA6E783408172
/* 20230601 */
BasePlus: F*B3CACDA32A5E70940E667DCA859483BD76DB082D19BAF326F28A580226DDD962
/* 20230526 */
BasePlus: F*2A4F3953EC56DB914024457F74286D565C23DCF220FF151040BDB704FD8DDB06
/* 20230520 */
BasePlus: F*0CCAA009D64CC20ED315FA123C233E0383967E635EB8708E7A48EEE3767C6BC5
/* 20230503 */
BasePlus: F*B297440903337E1AE6F12A6001B80B8AB743079847D16D63DF1C649AE51AA411
/* 20230419 */
BasePlus: F*625E56B017C4AA8D436959C0A03C8503773A9A3823D43FA9E0326276E52DA6F2
/* 20230417 */
BasePlus: F*F39F38CE80A5D8EED3BC9F2413CD6DEF38E8657E5DCF427CBA8938EB8C4350B6
/* 20230411 */
BasePlus: F*B5BF05531BF78DCEBC436BD93311FED0436D83AA3D106ABFBAD96B04C7D63DF2
DFA: F*924711C77E413B8CFC18336DDA2293A9F5294D02E267C1BB7BC876B4AF0AABE4
dynMacroArray: F*6E087F38BB39B93CBF983124272812E14693C4EF5EE0A3A218BD2BAA069A74BF
GSM: F*91C619E47EFAB44CCEB8B892BA1D7A8F9948590DA1317B8EA330F5D12642CE0E
macroArray: F*85E3BE4D163AC5223B6EC9D3C25C46564A656E3830998B4555A963180D767160
SQLinDS: F*3BB422E8C94515DEE9E13E674A0D119794F464D9597C28D5D536E71F64EB5298
/* 20230401 */
BasePlus: F*AD0B78F94A6FD1C394999CBBC8DD16017FB06DFC3FA1F51AC17B43AC8F517432
/* 20230210 */
SQLinDS: F*229ACF1A62E5194A25C75D8E554BEF1B7D29227A498ED5862F23892BB0D57644
/* 20221215 */
BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -18,7 +18,7 @@
---
# The DFA package [ver. 0.5.4] <a name="dfa-package"></a> ###############################################
# The DFA package [ver. 0.5.6] <a name="dfa-package"></a> ###############################################
The **DFA** (a.k.a. *Dynamic Function Array*) package implements:
- dynamic numeric and character arrays,
@@ -52,10 +52,10 @@ Package contains:
12. exec generatearrays
13. clean generatearrays
*SAS package generated by generatePackage, version 20221215*
*SAS package generated by generatePackage, version 20230905*
The SHA256 hash digest for package BasePlus:
`6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034`
The SHA256 hash digest for package DFA:
`F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62`
---
# Content description ############################################################################################

Binary file not shown.

Binary file not shown.

View File

@@ -8,7 +8,7 @@
---
# The GSM package [ver. 0.20.4] <a name="gsm-package"></a> ###############################################
# The GSM package [ver. 0.21.1] <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.
@@ -91,10 +91,10 @@ Package contains:
Required SAS Components:
`Base SAS Software`
*SAS package generated by generatePackage, version 20221215*
*SAS package generated by generatePackage, version 20230905*
The SHA256 hash digest for package GSM:
`83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524`
`F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682`
## >>> `%GSM()` macro: <<< <a name="gsm-macro"></a> #######################
@@ -143,6 +143,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
<,encodingRestricted=>
<,secret=>
<,lineEnd=>
<,encrypt=>
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -182,10 +183,16 @@ The basic syntax is the following, the `<...>` means optional parameters:
`0A` for line feed, `0D` for carriage return,
`0D0A` for both, and `20` for space.
* `encrypt=` - *Optional*, the default value is `ENCRYPT`.
Indicate if `FCMP` functions generated by the package
are encrypted. Value has to be either empty or `ENCRYPT`,
all other are converted to default. The option is
dedicated for debugging, keep the default value
for production use.
* `trim=` - *Deprecated*, the default value is `0`.
*Kept for backward compatibility.*
---
### Example: ###################################################################

Binary file not shown.

View File

@@ -19,7 +19,7 @@
---
# The macroArray package [ver. 1.0.4] <a name="macroarray-package"></a> ###############################################
# The macroArray package [ver. 1.0.6] <a name="macroarray-package"></a> ###############################################
The **macroArray** package implements a macro array facility:
- `%array()`,
@@ -75,10 +75,10 @@ Package contains:
Required SAS Components:
*Base SAS Software*
*SAS package generated by generatePackage, version 20221215*
*SAS package generated by generatePackage, version 20230905*
The SHA256 hash digest for package macroArray:
`8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470`
`F*4FAAEE7DF2854EA31933AE017A89C1615C7291A66A07CCE345041EB0D587ED4E`
---
# Content description ############################################################################################
@@ -278,6 +278,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
<,macarray=N>
<,ds=>
<,vars=>
<,q=>
)
~~~~~~~~~~~~~~~~~~~~~~~
@@ -312,8 +313,8 @@ The basic syntax is the following, the `<...>` means optional parameters:
`%array(myArr[*] x1-x3 (4:6), vnames=Y)`
will use `x1`, `x2`, and `x3` as values instead `4`, `5`, and `6`.
* `macarray=N` - *Optional*, default value `N`, if set to `Y`/`YES` then macro named with array
name is compiled to create convenient envelope for multiple ampersands, e.g.
* `macarray=N` - *Optional*, default value `N`, if set to `Y`/`YES` then a macro, named with the array
name, is compiled to create convenient envelope for multiple ampersands, e.g.
`%array(myArr[*] x1-x3 (4:6), macarray=Y)`
will create `%myArr(J)` macro which will allow to extract "data"
from macroarray like:
@@ -325,8 +326,8 @@ The basic syntax is the following, the `<...>` means optional parameters:
macrovariables with prefix like the array name and numeric suffixes,
then the minimum and the maximum index is determined
and all not existing global macrovariables are created and
a macro is generated in the same way as for the `Y` value
a macro is generated in the same way as for the `Y` value.
* `ds=` - *Optional*, use a dataset as a basis for a macroarray data,
if used by default overwrites use of the `array` parameter, honors `macarray=`
argument, dataset options are allowed, e.g. `sashelp.class(obs=5)`
@@ -343,23 +344,27 @@ The basic syntax is the following, the `<...>` means optional parameters:
2) macroarray "WEIGHT" with ALL(no separator is equivalent to #)
values of variable "weight" <br>
3) macroarray "W" with UNIQUE(|) values of variable "weight" and <br>
4) macroarray "AGE" with UNIQUE(|) values of variable "age",
4) macroarray "AGE" with UNIQUE(|) values of variable "age".
* `q=` - *Optional*, indicates (when set to `1`) if the value be surrounded by quotes.
It uses `quote(cats(...))` combo under the hood. Default value is `0`.
Ignored for `macarray=M`.
---
### EXAMPLES AND USECASES: ####################################################
**EXAMPLE 1.** Basic use-case.
Creating macroarray like in the array statement;
values are used by default;
different types of brackets are allowed;
Creating macroarray like in the array statement.
Values not variables names are used by default.
Different types of brackets are allowed.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%array(a[*] x1-x5 (1:5))
%array(b{5} (5*17))
%array(b{5} (5*17), q=1)
%* Mind the $ since it is a character array!;
%array(c(3) $ 10 ("a A" "b,B" "c;C"))
@@ -405,7 +410,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
%put &=g0. &=g1. &=g2.;
%* Or something more complex;
%array(gg[0:11] $ 11, function = put(intnx("MONTH", '1jun2018'd, _I_, "E"), yymmn.))
%array(gg[0:11] $ 11, function = put(intnx("MONTH", '1jun2018'd, _I_, "E"), yymmn.), q=1)
%put &=ggLBOUND. &=ggHBOUND. &=ggN.;
%put &=gg0 &=gg1 &=gg2 ... &=gg11;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -433,10 +438,10 @@ The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 6a.** "Uppercas Letters"
**EXAMPLE 6a.** Quoted "Uppercas Letters"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%array(UL[26] $, function = byte(rank("A")+_I_-1) )
%array(UL[26] $, function = byte(rank("A")+_I_-1) , q=1)
%put &=UL1 &=UL2 ... &=UL25 &=UL26;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -451,7 +456,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
%* The range handling, warning;
%put *%ll(265)*;
%* The input mode;
%put *before:*%ll(2)*;
%let %ll(2,I) = bbbbb;
@@ -576,10 +581,10 @@ The basic syntax is the following, the `<...>` means optional parameters:
Currently the only separator in VARS is a space.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%array(ds = sashelp.class, vars = height#h weight weight|w age|)
%array(ds = sashelp.class, vars = height#h weight weight|w age|, q=1)
%put _user_;
%array(ds = sashelp.class, vars = height#hght weight weight|wght age|, macarray=Y)
%array(ds = sashelp.class, vars = height#hght weight weight|wght age|, macarray=Y, q=1)
%put *%hght(&hghtLBOUND.)**%weight(2)**%wght(&wghtHBOUND.)**%age(3)*;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -599,7 +604,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
%let myTest6 = 16;
%let myTest9 = 19;
%array(myTest, macarray=M)
%array(myTest, macarray=M, q=1)
%do_over(myTest, phrase = %nrstr(%put *&_I_.*%myTest(&_I_.)*;))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Binary file not shown.

View File

@@ -8,16 +8,19 @@
---
# The SQLinDS package [ver. 2.2.4] <a name="sqlinds-package"></a> ###############################################
# The SQLinDS package [ver. 2.2.7] <a name="sqlinds-package"></a> ###############################################
The **SQLinDS** package is an implementation of
the *macro-function-sandwich* concept introduced in the
*"Use the Full Power of SAS in Your Function-Style Macros"*,
the article by *Mike Rhoads (Westat, Rockville)*.
Copy of the article is available at:
The article is available at:
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
Copy of the article can also be found in *additional content* directory.
Package provides ability to *execute* SQL queries inside a data step, e.g.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
data class;
@@ -46,10 +49,10 @@ Package contains:
Required SAS Components:
*Base SAS Software*
*SAS package generated by generatePackage, version 20221215*
*SAS package generated by generatePackage, version 20230905*
The SHA256 hash digest for package SQLinDS:
`42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0`
`F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9`
---
# Content description ############################################################################################
@@ -96,6 +99,8 @@ Based on the article *"Use the Full Power of SAS in Your Function-Style Macros"*
by *Mike Rhoads* (Westat, Rockville), available at:
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
Copy of the article can also be found in *additional content* directory.
### SYNTAX: ###################################################################
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%sql(<nonempty sql querry code>)

Binary file not shown.