From f69a2a8da1fd9d23e1f704587d105c00a80f8d74 Mon Sep 17 00:00:00 2001 From: yabwon Date: Sun, 10 Nov 2019 16:56:36 +0100 Subject: [PATCH] update in version checking update in version checking --- dfa.zip | Bin 27160 -> 27267 bytes dynmacroarray.zip | Bin 10260 -> 10277 bytes generatePackage.sas | 153 +++-- generatePackage.sas_bckp2 | 1167 +++++++++++++++++++++++++++++++++++++ macroarray.zip | Bin 23444 -> 23551 bytes sqlinds.zip | Bin 9289 -> 9395 bytes 6 files changed, 1260 insertions(+), 60 deletions(-) create mode 100644 generatePackage.sas_bckp2 diff --git a/dfa.zip b/dfa.zip index 657530af37255f4422bac10e9aaebef2c2bb35ab..8974ac50dc2a7a5aebe84f92e41741d435e41424 100644 GIT binary patch delta 5037 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 H-*5i~LUJxo delta 4890 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 W|CJ@5BNYk?T-A{mQ`7eE@&5sOLiEi5 diff --git a/dynmacroarray.zip b/dynmacroarray.zip index 3a5cf0421b50a2438ed0a3cf769b3ed62d27622a..0bd0b9761917f44925943a37d84cf6ed04e84cd5 100644 GIT binary patch delta 3899 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 y6v&0MY(V`YRg% delta 3901 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 b{^@9dsgpYGF(w6~YQ^kG$^C^am%e diff --git a/generatePackage.sas b/generatePackage.sas index 7aed603..0793a45 100644 --- a/generatePackage.sas +++ b/generatePackage.sas @@ -1,4 +1,4 @@ -/*** HELP START ***/ +/*** HELP START ***/ /**############################################################################**/ /* */ @@ -538,7 +538,7 @@ data _null_; packageReqPackages = lowcase(symget('packageReqPackages')); /* try to load required packages */ put 'data _null_ ; '; - put ' length req name $ 64 SYSloadedPackages $ 32767; '; + put ' length req name $ 64 vers verR 8 SYSloadedPackages $ 32767; '; put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; put ' do; '; put ' do until(EOF); '; @@ -550,19 +550,24 @@ data _null_; put ' declare hash LP(); '; put ' LP.defineKey("name"); '; + put ' LP.defineData("vers"); '; put ' LP.defineDone(); '; put ' do _N_ = 1 to countw(SYSloadedPackages); '; - put ' name = scan(SYSloadedPackages, _N_); '; + put ' req = scan(SYSloadedPackages, _N_, " "); '; + put ' name = lowcase(strip(scan(req, 1, "("))); '; + put ' vers = input(compress(scan(req,-1, "("), ".", "KD"),best32.); '; put ' _RC_ = LP.add(); '; put ' end; '; put ' do req = ' / packageReqPackages / ' ; '; - put ' name = lowcase(strip(scan(req, 1, " "))); '; - put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; - put ' if LP.check() ne 0 then '; +/* put ' req = compress(req, "(.)", "KDF"); ';*/ + put ' name = lowcase(strip(scan(req, 1, "("))); '; + put ' verR = input(compress(scan(req,-1, "("), ".", "KD"),best32.); vers = .; '; + put ' LP_find = LP.find(); '; + put ' if (LP_find ne 0) or (LP_find = 0 and . < vers < verR) then '; put ' do; '; put ' put "NOTE: Trying to install required SAS package " req; '; - put ' call execute(cats(''%nrstr(%loadPackage('', name, ", requiredVersion = ", vers, "))")); '; + put ' call execute(cats(''%nrstr(%loadPackage('', name, ", requiredVersion = ", verR, "))")); '; put ' end ; '; put ' end ; '; put ' stop; '; @@ -581,21 +586,26 @@ data _null_; put ' declare hash LP(); '; put ' LP.defineKey("name"); '; + put ' LP.defineData("vers"); '; put ' LP.defineDone(); '; put ' do _N_ = 1 to countw(SYSloadedPackages); '; - put ' name = scan(SYSloadedPackages, _N_); '; + put ' req = scan(SYSloadedPackages, _N_, " "); '; + put ' name = lowcase(strip(scan(req, 1, "("))); '; + put ' vers = input(compress(scan(req,-1, "("), ".", "KD"),best32.); '; put ' _RC_ = LP.add(); '; put ' end; '; put ' missingPackagr = 0; '; put ' do req = ' / packageReqPackages / ' ; '; - put ' name = lowcase(strip(scan(req, 1, " "))); '; - put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; - put ' if LP.check() ne 0 then '; +/* put ' req = compress(req, "(.)", "KDF"); ';*/ + put ' name = lowcase(strip(scan(req, 1, "("))); '; + put ' verR = input(compress(scan(req,-1, "("), ".", "KD"),best32.); vers = .; '; + put ' LP_find = LP.find(); '; + put ' if (LP_find ne 0) or (LP_find = 0 and . < vers < verR) then '; put ' do; '; put ' missingPackagr = 1; '; put ' put "ERROR: SAS package " req "is missing! Download it and" ; '; - put ' put ''ERROR- use %loadPackage('' name ", requiredVersion = " vers ") to load it." ;'; + put ' put ''ERROR- use %loadPackage('' name ", requiredVersion = " verR ") to load it." ;'; put ' end ; '; put ' end ; '; put ' if missingPackagr then call symputX("packageRequiredErrors", 1, "L"); '; @@ -605,8 +615,8 @@ data _null_; put ' put "ERROR: No package loaded!"; '; put ' call symputX("packageRequiredErrors", 1, "L"); '; put ' do req = ' / packageReqPackages / ' ; '; - put ' name = lowcase(strip(scan(req, 1, " "))); '; - put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; + put ' name = lowcase(strip(scan(req, 1, "("))); '; + put ' vers = lowcase(compress(scan(req,-1, "("), ".", "KD")); '; put ' put "ERROR: SAS package " req "is missing! Download it and" ; '; put ' put ''ERROR- use %loadPackage('' name ", requiredVersion = " vers ") to load it." ; '; put ' end ; '; @@ -673,31 +683,31 @@ data _null_; end; /* update SYSloadedPackages global macrovariable */ - put ' data _null_ ; '; - put ' length SYSloadedPackages $ 32767; '; - put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; - put ' do; '; - put ' do until(EOF); '; - put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; - put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; - put ' end; '; - put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; + put ' data _null_ ; '; + put ' length SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; - put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.)#') = 0 then "; - put ' do; '; - put " SYSloadedPackages = catx('#', SYSloadedPackages, '&packageName.'); "; - put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; - put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; - put ' put "NOTE: " SYSloadedPackages = ; '; - put ' end ; '; - put ' end; '; - put ' else '; - put ' do; '; - put " call symputX('SYSloadedPackages', '&packageName.', 'G'); "; - put " put 'NOTE: SYSloadedPackages = &packageName.'; "; - put ' end; '; - put ' stop; '; - put 'run; ' / ; + put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.(&packageVersion.))#') = 0 then "; + put ' do; '; + put " SYSloadedPackages = catx('#', SYSloadedPackages, '&packageName.(&packageVersion.)'); "; + put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; + put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; + put ' put "NOTE: " SYSloadedPackages = ; '; + put ' end ; '; + put ' end; '; + put ' else '; + put ' do; '; + put " call symputX('SYSloadedPackages', '&packageName.(&packageVersion.)', 'G'); "; + put " put 'NOTE: SYSloadedPackages = &packageName.(&packageVersion.)'; "; + put ' end; '; + put ' stop; '; + put 'run; ' / ; put '%put NOTE- ;'; put '%put NOTE: '"Loading package &packageName., version &packageVersion., license &packageLicense.;"; @@ -862,13 +872,13 @@ data _null_; %do; length packageReqPackages $ 32767; packageReqPackages = lowcase(symget('packageReqPackages')); - /* try to load required packages */ + /* note to unload required packages */ put 'data _null_ ; '; put ' length req name $ 64; '; put ' put "NOTE-" / "NOTE: To unload additional required SAS packages execute: " / "NOTE-"; '; put ' do req = ' / packageReqPackages / ' ; '; - put ' name = strip(scan(req, 1, " ")); '; - put ' put ''NOTE- %unloadPackage( '' name ")" ; '; + put ' name = strip(scan(req, 1, "(")); '; + put ' put '' %unloadPackage( '' name ")" ; '; put ' end ; '; put ' put "NOTE-" / "NOTE-"; stop; '; put 'run; '; @@ -876,26 +886,26 @@ data _null_; /* update SYSloadedPackages global macrovariable */ - put ' data _null_ ; '; - put ' length SYSloadedPackages $ 32767; '; - put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; - put ' do; '; - put ' do until(EOF); '; - put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; - put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; - put ' end; '; - put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; + put ' data _null_ ; '; + put ' length SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; - put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.)#') > 0 then "; - put ' do; '; - put " SYSloadedPackages = tranwrd(SYSloadedPackages, '#&packageName.#', '##'); "; - put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; - put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; - put ' put "NOTE: " SYSloadedPackages = ; '; - put ' end ; '; - put ' end; '; - put ' stop; '; - put 'run; ' / ; + put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.(&packageVersion.))#') > 0 then "; + put ' do; '; + put " SYSloadedPackages = tranwrd(SYSloadedPackages, '#&packageName.(&packageVersion.)#', '##'); "; + put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; + put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; + put ' put "NOTE: " SYSloadedPackages = ; '; + put ' end ; '; + put ' end; '; + put ' stop; '; + put 'run; ' / ; put '%put NOTE: '"Unloading package &packageName., version &packageVersion., license &packageLicense.;"; @@ -943,6 +953,29 @@ data _null_; put ' if upcase(strip(_infile_)) = "DESCRIPTION START:" then printer = 1; '; put ' end; '; put ' else stop; '; + + %if %bquote(&packageReqPackages.) ne %then + %do; + length packageReqPackages $ 32767; + packageReqPackages = symget('packageReqPackages'); + put ' length req $ 64; '; + put ' put ; put " Required SAS Packages: "; '; + put ' do req = ' / packageReqPackages / ' ; '; + put ' put " " req; '; + put ' end ; '; + %end; + + %if %bquote(&packageRequired.) ne %then + %do; + length packageRequired $ 32767; + packageRequired = symget('packageRequired'); + put ' length req $ 64; '; + put ' put ; put " Required SAS Components: "; '; + put ' do req = ' / packageRequired / ' ; '; + put ' put " " req; '; + put ' end ; '; + %end; + put 'run; ' /; /* license info */ diff --git a/generatePackage.sas_bckp2 b/generatePackage.sas_bckp2 new file mode 100644 index 0000000..7aed603 --- /dev/null +++ b/generatePackage.sas_bckp2 @@ -0,0 +1,1167 @@ +/*** HELP START ***/ + +/**############################################################################**/ +/* */ +/* Copyright Bartosz Jablonski, September 2019. */ +/* */ +/* Code is free and open source. If you want - you can use it. */ +/* I tested it the best I could */ +/* but it comes with absolutely no warranty whatsoever. */ +/* If you cause any damage or something - it will be your own fault. */ +/* You've been warned! You are using it on your own risk. */ +/* However, if you decide to use it don't forget to mention author: */ +/* Bartosz Jablonski (yabwon@gmail.com) */ +/* */ +/* Here is the official version: */ +/* + Copyright (c) 2019 Bartosz Jablonski (yabwon@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ +/**#############################################################################**/ + +/* Macros to generate SAS packages */ +/* A SAS package is a zip file containing a group + of SAS codes (macros, functions, datasteps generating + data, etc.) wrapped up together and %INCLUDEed by + a single load.sas file (also embedded inside the zip). +*/ + +/*** HELP END ***/ + + +/*** HELP START ***/ +%macro generatePackage( + /* location of package files */ + filesLocation=%sysfunc(pathname(work))/%lowcase(&packageName.) +)/secure; +/*** HELP END ***/ +%local zipReferrence filesWithCodes _DESCR_ _LIC_ _RC_ _PackageFileref_; +%let zipReferrence = _%sysfunc(datetime(), hex6.)_; +%let filesWithCodes = WORK._%sysfunc(datetime(), hex16.)_; +%let _DESCR_ = _%sysfunc(datetime(), hex6.)d; +%let _LIC_ = _%sysfunc(datetime(), hex6.)l; + +/* collect package metadata from the description.sas file */ +filename &_DESCR_. "&filesLocation./description.sas" lrecl = 256; +/* file contains licence */ +filename &_LIC_. "&filesLocation./license.sas" lrecl = 256; + +%if %sysfunc(fexist(&_DESCR_.)) %then + %do; + %put NOTE: Creating package%str(%')s metadata; + + %local packageName /* name of the package, required */ + packageVersion /* version of the package, required */ + packageTitle /* title of the package, required*/ + packageAuthor /* required */ + packageMaintainer /* required */ + packageEncoding /* required */ + packageLicense /* required */ + packageRequired /* optional */ + packageReqPackages /* optional */ + ; + data _null_; + infile &_DESCR_.; + input; + + select; + when(upcase(scan(_INFILE_, 1, ":")) = "PACKAGE") call symputX("packageName", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "VERSION") call symputX("packageVersion", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "AUTHOR") call symputX("packageAuthor", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "MAINTAINER") call symputX("packageMaintainer", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "TITLE") call symputX("packageTitle", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "ENCODING") call symputX("packageEncoding", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "LICENSE") call symputX("packageLicense", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "REQUIRED") call symputX("packageRequired", scan(_INFILE_, 2, ":"),"L"); + when(upcase(scan(_INFILE_, 1, ":")) = "REQPACKAGES") call symputX("packageReqPackages", scan(_INFILE_, 2, ":"),"L"); + + /* stop at the beginning of description */ + when(upcase(scan(_INFILE_, 1, ":")) = "DESCRIPTION START") stop; + otherwise; + end; + run; + + /* test for required descriptors */ + %if (%nrbquote(&packageName.) = ) + or (%nrbquote(&packageVersion.) = ) + or (%nrbquote(&packageAuthor.) = ) + or (%nrbquote(&packageMaintainer.) = ) + or (%nrbquote(&packageTitle.) = ) + or (%nrbquote(&packageEncoding.) = ) + or (%nrbquote(&packageLicense.) = ) + %then + %do; + %put ERROR: At least one of descriptors is missing!; + %put ERROR- They are required to create package.; + %put ERROR- &=packageName.; + %put ERROR- &=packageTitle.; + %put ERROR- &=packageVersion.; + %put ERROR- &=packageAuthor.; + %put ERROR- &=packageMaintainer.; + %put ERROR- &=packageEncoding.; + %put ERROR- &=packageLicense.; + %put ERROR- ; + %abort; + %end; + /* test for package name */ + %if %sysfunc(lengthn(&packageName.)) > 24 %then + %do; + %put ERROR: Package name is more than 24 characters long.; + %put ERROR- The name is used for functions%str(%') dataset name; + %put ERROR- and for formats%str(%') cataloge name (with suffix).; + %put ERROR- The length is %sysfunc(lengthn(&packageName.)). Try something shorter.; + %abort; + %end; + %else %if %sysfunc(lengthn(&packageName.)) < 3 %then + %do; + %put WARNING: Package name is less than 3 characters.; + %put WARNING- Maybe consider some _meaningful_ name?; + %end; + /* test characters in package name */ + %if %qsysfunc(lengthn(%qsysfunc(compress(&packageName.,,KDF)))) NE %qsysfunc(lengthn(&packageName.)) %then + %do; + %put ERROR: Package name contains illegal symbols.; + %put ERROR- The name is used for functions%str(%') dataset name; + %put ERROR- and for formats%str(%') cataloge name.; + %put ERROR- Only English letters, underscore(_), and digits are allowed.; + %put ERROR- Try something else. Maybe: %qsysfunc(compress(&packageName.,,KDF)) will do?; + %abort; + %end; + + %end; +%else + %do; + %put ERROR: The description.sas file is missing!; + %put ERROR- The file is required to create package%str(%')s metadata; + %abort; + %end; + +/* generate package fileref with MD5 to allow + different file reference for each package + while loading package with %loadPackage() macro + */ +%let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); + +/* test if version is a number */ +data _null_; + version = input("&packageVersion.", ?? best32.); + if not (version > 0) then + do; + put 'ERROR: Package version should be a positive NUMBER.'; + put 'ERROR- Current value is: ' "&packageVersion."; + put 'ERROR- Try something small, e.g. 0.1'; + put; + abort; + end; +run; + +/* create or replace the ZIP file for package */ +filename &zipReferrence. ZIP "&filesLocation./%lowcase(&packageName.).zip"; + +%if %sysfunc(fexist(&zipReferrence.)) %then + %do; + %put NOTE: Deleting file "&filesLocation./%lowcase(&packageName.).zip"; + %let _RC_ = %sysfunc(fdelete(&zipReferrence.)); + %end; + +/*** HELP START ***/ +/* + Locate all files with code in base folder (i.e. at filesLocation directory) +*/ +/* + Remember to prepare the description.sas file for you package. + The colon (:) is a field separator and is restricted + in lines of the header part. + The file should contain the following obligatory information: +-------------------------------------------------------------------------------------------- +>> **HEADER** << +Type: Package +Package: ShortPackageName +Title: A title/brief info for log note about your packages +Version: X.Y +Author: Firstname1 Lastname1 (xxxxxx1@yyyyy.com), Firstname2 Lastname2 (xxxxxx2@yyyyy.com) +Maintainer: Firstname Lastname (xxxxxx@yyyyy.com) +License: MIT +Encoding: UTF8 + +Required: "Base SAS Software" :%*optional, COMMA separated, QUOTED list, names of required SAS products, values must be like from proc setinit;run; output *; +ReqPackages: "macroArray (0.1)", "DFA (0.1)" :%*optional, COMMA separated, QUOTED list, names of required packages *; + +>> **DESCRIPTION** << +>> All the text below will be used in help << +DESCRIPTION START: + Xxxxxxxxxxx xxxxxxx xxxxxx xxxxxxxx xxxxxxxx. Xxxxxxx + xxxx xxxxxxxxxxxx xx xxxxxxxxxxx xxxxxx. Xxxxxxx xxx + xxxx xxxxxx. Xxxxxxxxxxxxx xxxxxxxxxx xxxxxxx. +DESCRIPTION END: +-------------------------------------------------------------------------------------------- + + Name of the 'type' of folder and files.sas inside must be in _low_ case letters. + + If order of loading is important, the 'sequential number' + can be used to order multiple types in the way you wish. + + The "tree structure" of the folder could be for example as follows: + +-------------------------------------------------------------------------------------------- + + .. + | + +-000_libname [one file one libname] + | | + | +-abc.sas [a file with a code creating libname ABC] + | + +-001_macro [one file one macro] + | | + | +-hij.sas [a file with a code creating macro HIJ] + | | + | +-klm.sas [a file with a code creating macro KLM] + | + +-002_function [one file one function, + | | option OUTLIB= should be: work.&packageName.fcmp.package + | | option INLIB= should be: work.&packageName.fcmp + | | (both literally with macrovariable name and "fcmp" sufix)] + | | + | +-efg.sas [a file with a code creating function EFG] + | + +-003_format [one file one format, + | | option LIB= should be: work.&packageName.format + | | (literally with macrovariable name and "format" sufix)] + | | + | +-efg.sas [a file with a code creating format EFG and informat EFG] + | + +-004_data [one file one dataset] + | | + | +-abc.efg.sas [a file with a code creating dataset EFG in library ABC] + | + +-005_exec [so called "free code", content of the files will be printed + | | to the log before execution] + | | + | +- + | + +-006_format [if your codes depend each other you can order them in folders, + | | e.g. code from 003_... will be executed before 006_...] + | | + | +-abc.sas [a file with a code creating format ABC, + | used in the definition of the format EFG] + +-007_function + | | + | +- + | + +-_ + | + +-... + | + +-00n_clean [if you need to clean something up after exec file execution, + | | content of the files will be printed to the log before execution] + | | + | +- + +-... + ... +-------------------------------------------------------------------------------------------- + +*/ +/*** HELP END ***/ + +/* collect the data */ +data &filesWithCodes.; + base = "&filesLocation."; + length folder file lowcase_name $ 256 folderRef fileRef $ 8; + drop lowcase_name; + + folderRef = "_%sysfunc(datetime(), hex6.)0"; + + rc=filename(folderRef, base); + folderid=dopen(folderRef); + + do i=1 to dnum(folderId); drop i; + folder = dread(folderId, i); + if folder NE lowcase(folder) then + do; + put 'ERROR: Folder should be named ONLY with low case letters.'; + put 'ERROR- Current value is: ' folder; + lowcase_name = lowcase(folder); + put 'ERROR- Try: ' lowcase_name; + put; + abort; + end; + order = scan(folder, 1, "_"); + type = scan(folder,-1, "_"); + + fileRef = "_%sysfunc(datetime(), hex6.)1"; + rc = filename(fileRef, catx("/", base, folder)); + fileId = dopen(fileRef); + + file = ' '; + 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: ' lowcase_name; + put; + abort; + end; + fileshort = substr(file, 1, length(file) - 4); /* filename.sas -> filename */ + output; + end; + rc = dclose(fileId); + rc = filename(fileRef); + end; + + rc = dclose(folderid); + rc = filename(folderRef); + stop; +run; +proc sort data = &filesWithCodes.; + by order type file; +run; +/* +proc contents data = &filesWithCodes.; +run; +*/ +title1 "Package's location is: &filesLocation."; +title2 "User: &SYSUSERID., datetime: %qsysfunc(datetime(), datetime21.), SAS version: &SYSVLONG4."; +title3 "Package's encoding: '&packageEncoding.', session's encoding: '&SYSENCODING.'."; +title4 " ______________________________ "; +title5 "List of files for package: &packageName. (version &packageVersion.), license: &packageLicense."; +title6 "MD5 hashed fileref of package lowcase name: &_PackageFileref_."; +%if (%bquote(&packageRequired.) ne ) + or (%bquote(&packageReqPackages.) ne ) +%then + %do; + title7 "Required SAS licences: %qsysfunc(compress(%bquote(&packageRequired.), %str(%'%")))" ; /* ' */ + title8 "Required SAS packages: %qsysfunc(compress(%bquote(&packageReqPackages.),%str(%'%")))" ; /* " */ + %end; + + +proc print data = &filesWithCodes.(drop=base); +run; +title; + +/* packages description */ +data _null_; + infile &_DESCR_.; + file &zipReferrence.(description.sas); + input; + put _INFILE_; +run; + +/* package license */ +%if %sysfunc(fexist(&_LIC_.)) %then + %do; + data _null_; + infile &_LIC_.; + file &zipReferrence.(license.sas); + input; + put _INFILE_; + run; + %end; +%else + %do; + %put WARNING:[License] No license.sas file provided, default (MIT) licence file will be generated.; + %let packageLicense = MIT; + data _null_; + file &zipReferrence.(license.sas); + put " "; + put " Copyright (c) %sysfunc(today(),year4.) &packageAuthor. "; + put " "; + put " Permission is hereby granted, free of charge, to any person obtaining a copy "; + put ' of this software and associated documentation files (the "Software"), to deal '; + put " in the Software without restriction, including without limitation the rights "; + put " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell "; + put " copies of the Software, and to permit persons to whom the Software is "; + put " furnished to do so, subject to the following conditions: "; + put " "; + put " The above copyright notice and this permission notice shall be included "; + put " in all copies or substantial portions of the Software. "; + put " "; + put ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR '; + put " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, "; + put " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE "; + put " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "; + put " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, "; + put " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE "; + put " SOFTWARE. "; + put " "; + run; + %end; + +/* package metadata */ +data _null_; + if 0 then set &filesWithCodes. nobs=NOBS; + if NOBS = 0 then + do; + putlog "WARNING:[&sysmacroname.] No files to create package."; + stop; + end; + file &zipReferrence.(packagemetadata.sas); + + put ' data _null_; '; /* simple "%local" returns error while loading package */ + put ' call symputX("packageName", " ", "L");'; + put ' call symputX("packageVersion", " ", "L");'; + put ' call symputX("packageTitle", " ", "L");'; + put ' call symputX("packageAuthor", " ", "L");'; + put ' call symputX("packageMaintainer", " ", "L");'; + put ' call symputX("packageEncoding", " ", "L");'; + put ' call symputX("packageLicense", " ", "L");'; + put ' run; '; + + put ' %let packageName =' "&packageName.;"; + put ' %let packageVersion =' "&packageVersion.;"; + put ' %let packageTitle =' "&packageTitle.;"; + put ' %let packageAuthor =' "&packageAuthor.;"; + put ' %let packageMaintainer =' "&packageMaintainer.;"; + put ' %let packageEncoding =' "&packageEncoding.;"; + put ' %let packageLicense =' "&packageLicense.;"; + put ' ; '; + + stop; +run; + +/* loading package files */ +data _null_; + if NOBS = 0 then stop; + + file &zipReferrence.(load.sas) lrecl=32767; + + put "filename &_PackageFileref_. list;" /; + put ' %put NOTE- ;'; + put ' %put NOTE: ' @; put "Loading package &packageName., version &packageVersion., license &packageLicense.; "; + put ' %put NOTE: ' @; put "*** &packageTitle. ***; "; + put ' %put NOTE- ' @; put "Generated: %sysfunc(datetime(), datetime21.); "; + put ' %put NOTE- ' @; put "Author(s): &packageAuthor.; "; + put ' %put NOTE- ' @; put "Maintainer(s): &packageMaintainer.; "; + put ' %put NOTE- ;'; + put ' %put NOTE- Write %nrstr(%%)helpPackage(' "&packageName." ') for the description;'; + put ' %put NOTE- ;'; + put ' %put NOTE- *** START ***; ' /; + + put '%include ' " &_PackageFileref_.(packagemetadata.sas) / nosource2; " /; /* <- copied also to loadPackage macro */ + isFunction = 0; + isFormat = 0; + + %if (%bquote(&packageRequired.) ne ) + or (%bquote(&packageReqPackages.) ne ) + %then + %do; + put ' data _null_; '; + put ' call symputX("packageRequiredErrors", 0, "L"); '; + put ' run; '; + %end; + + %if %bquote(&packageRequired.) ne %then + %do; + put ' %put NOTE- *Testing required SAS components*%sysfunc(DoSubL( '; /* DoSubL() */ + put ' options nonotes nosource %str(;) '; + put ' options ls=max ps=max %str(;) '; + put ' /* temporary redirect log */ '; + put ' filename _stinit_ TEMP %str(;) '; + put ' proc printto log = _stinit_ %str(;) run %str(;) '; + put ' /* print out setinit */ '; + put ' proc setinit %str(;) run %str(;) '; + put ' proc printto %str(;) run %str(;) '; + + put ' data _null_ %str(;) '; + put ' /* loadup checklist of required SAS components */ '; + put ' if _n_ = 1 then '; + put ' do %str(;) '; + put ' length req $ 256 %str(;) '; + put ' declare hash R() %str(;) '; + put ' _N_ = R.defineKey("req") %str(;) '; + put ' _N_ = R.defineDone() %str(;) '; + put ' declare hiter iR("R") %str(;) '; + length packageRequired $ 32767; + packageRequired = upcase(symget('packageRequired')); + put ' do req = %bquote(' / packageRequired / ') %str(;) '; + put ' _N_ = R.add(key:req,data:req) %str(;) '; + put ' end %str(;) '; + put ' end %str(;) '; + put ' '; + put ' /* read in output from proc setinit */ '; + put ' infile _stinit_ end=eof %str(;) '; + put ' input %str(;) '; + /*put ' put "*> " _infile_ %str(;)';*/ /* for testing */ + put ' '; + put ' /* if component is in setinit remove it from checklist */ '; + put ' if _infile_ =: "---" then '; + put ' do %str(;) '; + put ' req = upcase(substr(_infile_, 4, 64)) %str(;) '; + put ' if R.find(key:req) = 0 then '; + put ' do %str(;) '; + put ' _N_ = R.remove() %str(;) '; + put ' end %str(;) '; + put ' end %str(;) '; + put ' '; + put ' /* if checklist is not null rise error */ '; + put ' if eof and R.num_items > 0 then '; + put ' do %str(;) '; + put ' put "ERROR- ###########################################" %str(;) '; + put ' put "ERROR- The following SAS components are missing! " %str(;) '; + put ' call symputX("packageRequiredErrors", 1, "L") %str(;) '; + put ' do while(iR.next() = 0) %str(;) '; + put ' put "ERROR- " req %str(;) '; + put ' end %str(;) '; + put ' put "ERROR- ###########################################" %str(;) '; + put ' put %str(;) '; + put ' end %str(;) '; + put ' run %str(;) '; + put ' filename _stinit_ clear %str(;) '; + put ' options notes source %str(;) '; + put ' ))*; '; + %end; + + %if %bquote(&packageReqPackages.) ne %then + %do; + + length packageReqPackages $ 32767; + packageReqPackages = lowcase(symget('packageReqPackages')); + /* try to load required packages */ + put 'data _null_ ; '; + put ' length req name $ 64 SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' end; '; + put ' SYSloadedPackages = lowcase(SYSloadedPackages); '; + + put ' declare hash LP(); '; + put ' LP.defineKey("name"); '; + put ' LP.defineDone(); '; + put ' do _N_ = 1 to countw(SYSloadedPackages); '; + put ' name = scan(SYSloadedPackages, _N_); '; + put ' _RC_ = LP.add(); '; + put ' end; '; + + put ' do req = ' / packageReqPackages / ' ; '; + put ' name = lowcase(strip(scan(req, 1, " "))); '; + put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; + put ' if LP.check() ne 0 then '; + put ' do; '; + put ' put "NOTE: Trying to install required SAS package " req; '; + put ' call execute(cats(''%nrstr(%loadPackage('', name, ", requiredVersion = ", vers, "))")); '; + put ' end ; '; + put ' end ; '; + put ' stop; '; + put 'run; '; + + /* test if required packages are loaded */ + put 'data _null_ ; '; + put ' length req name $ 64 SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' SYSloadedPackages = lowcase(SYSloadedPackages); '; + + put ' declare hash LP(); '; + put ' LP.defineKey("name"); '; + put ' LP.defineDone(); '; + put ' do _N_ = 1 to countw(SYSloadedPackages); '; + put ' name = scan(SYSloadedPackages, _N_); '; + put ' _RC_ = LP.add(); '; + put ' end; '; + + put ' missingPackagr = 0; '; + put ' do req = ' / packageReqPackages / ' ; '; + put ' name = lowcase(strip(scan(req, 1, " "))); '; + put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; + put ' if LP.check() ne 0 then '; + put ' do; '; + put ' missingPackagr = 1; '; + put ' put "ERROR: SAS package " req "is missing! Download it and" ; '; + put ' put ''ERROR- use %loadPackage('' name ", requiredVersion = " vers ") to load it." ;'; + put ' end ; '; + put ' end ; '; + put ' if missingPackagr then call symputX("packageRequiredErrors", 1, "L"); '; + put ' end; '; + put ' else '; + put ' do; '; + put ' put "ERROR: No package loaded!"; '; + put ' call symputX("packageRequiredErrors", 1, "L"); '; + put ' do req = ' / packageReqPackages / ' ; '; + put ' name = lowcase(strip(scan(req, 1, " "))); '; + put ' vers = lowcase(compress(scan(req,-1, " "), ".", "KD")); '; + put ' put "ERROR: SAS package " req "is missing! Download it and" ; '; + put ' put ''ERROR- use %loadPackage('' name ", requiredVersion = " vers ") to load it." ; '; + put ' end ; '; + put ' end; '; + put ' stop; '; + put 'run; '; + %end; + + %if (%bquote(&packageRequired.) ne ) + or (%bquote(&packageReqPackages.) ne ) + %then + %do; + put ' data _null_; '; + put ' if symget("packageRequiredErrors") = "1" then '; + put ' do; '; + put ' put "ERROR: Loading package &packageName. will be aborted!";'; + put ' put "ERROR- Required SAS components are missing."; '; + put ' put "ERROR- *** STOP ***"; '; + put ' ABORT; '; + put ' end; '; + put ' run; '; + %end; + + do until(eof); + set &filesWithCodes. end = EOF nobs=NOBS; + if (upcase(type)=:'CLEAN') then continue; /* cleaning files are only included in unload.sas */ + put '%put NOTE- ;'; + put '%put NOTE- Element of type ' type 'from the file "' file +(-1) '" will be included;' /; + + 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; + + put '%include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;' /; + + isFunction + (upcase(type)=:'FUNCTION'); + isFormat + (upcase(type)=:'FORMAT'); + + /* add the link to the functions' dataset, only for the first occurrence */ + if 1 = isFunction and (upcase(type)=:'FUNCTION') then + do; + put "options APPEND=(cmplib = work.%lowcase(&packageName.fcmp));"; + put '%put NOTE- ;'; + put '%put NOTE:[CMPLIB] %sysfunc(getoption(cmplib));' /; + end; + + /* add the link to the formats' catalog, only for the first occurrence */ + if 1 = isFormat and (upcase(type)=:'FORMAT') then + do; + put "options INSERT=( fmtsearch = work.%lowcase(&packageName.format) );"; + put '%put NOTE- ;'; + put '%put NOTE:[FMTSEARCH] %sysfunc(getoption(fmtsearch));'/; + end; + end; + + /* update SYSloadedPackages global macrovariable */ + put ' data _null_ ; '; + put ' length SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; + + put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.)#') = 0 then "; + put ' do; '; + put " SYSloadedPackages = catx('#', SYSloadedPackages, '&packageName.'); "; + put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; + put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; + put ' put "NOTE: " SYSloadedPackages = ; '; + put ' end ; '; + put ' end; '; + put ' else '; + put ' do; '; + put " call symputX('SYSloadedPackages', '&packageName.', 'G'); "; + put " put 'NOTE: SYSloadedPackages = &packageName.'; "; + put ' end; '; + put ' stop; '; + put 'run; ' / ; + + put '%put NOTE- ;'; + put '%put NOTE: '"Loading package &packageName., version &packageVersion., license &packageLicense.;"; + put '%put NOTE- *** END ***;' /; + put "/* load.sas end */" /; + stop; +run; + +/* unloading package objects */ +data _null_; + /* break if no data */ + if NOBS = 0 then stop; + + file &zipReferrence.(unload.sas); + + put "filename &_PackageFileref_. list;" /; + put '%put NOTE: '"Unloading package &packageName., version &packageVersion., license &packageLicense.;"; + put '%put NOTE- *** START ***;' /; + + /* include "cleaning" files */ + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF nobs = NOBS; + if not (upcase(type)=:'CLEAN') then continue; + put '%put NOTE- Code of type ' type 'generated from the file "' file +(-1) '" will be executed;'; + 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- ;' /; + + put '%include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;' /; + end; + + /* delete macros and formats */ + put 'proc sql;'; + put ' create table WORK._%sysfunc(datetime(), hex16.)_ as'; + put ' select memname, objname, objtype'; + put ' from dictionary.catalogs'; + put ' where '; + put ' ('; + put ' objname in ("*"' /; + /* list of macros */ + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF nobs = NOBS; + if not (upcase(type)=:'MACRO') then continue; + put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;'; + put '%put NOTE- ;' /; + put ',"' fileshort upcase32. '"'; + end; + /**/ + put ' )'; + put ' and objtype = "MACRO"'; + put ' and libname = "WORK"'; + put ' )'; + put ' or'; + put ' ('; + put ' objname in ("*"' /; + /* list of formats */ + isFormat = 0; + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF; + if not (upcase(type)=:'FORMAT') then continue; + put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;'; + put '%put NOTE- ;' /; + put ',"' fileshort upcase32. '"'; + isFormat + 1; + end; + put ' )'; + put ' and objtype in ("FORMAT" "FORMATC" "INFMT" "INFMTC")'; + put ' and libname = "WORK"'; + put " and memname = '%upcase(&packageName.format)'"; + put ' )'; + + put ' order by objtype, memname, objname'; + put ' ;'; + put 'quit;'; + + put 'data _null_;'; + put ' do until(last.memname);'; + put ' set WORK._last_;'; + put ' by objtype memname;'; + put ' if first.memname then call execute("proc catalog cat = work." !! strip(memname) !! " force;");'; + put ' call execute("delete " !! strip(objname) !! " / et =" !! objtype !! "; run;");'; + put ' end;'; + put ' call execute("quit;");'; + put 'run;'; + put 'proc delete data = WORK._last_;'; + put 'run;'; + + /* delete the link to the formats catalog */ + if isFormat then + do; + put "proc delete data = work.%lowcase(&packageName.format)(mtype = catalog);"; + put 'run;'; + put 'options fmtsearch = (%unquote(%sysfunc(tranwrd(' / + '%lowcase(%sysfunc(getoption(fmtsearch)))' / + ',%str(' "work.%lowcase(&packageName.)format" '), %str() ))));'; + put 'options fmtsearch = (%unquote(%sysfunc(compress(' / + '%sysfunc(getoption(fmtsearch))' / + ', %str(()) ))));'; + put '%put NOTE:[FMTSEARCH] %sysfunc(getoption(fmtsearch));' /; + end; + + /* delete functions */ + put "proc fcmp outlib = work.%lowcase(&packageName.fcmp).package;"; + isFunction = 0; + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF; + if not (upcase(type)=:'FUNCTION') then continue; + put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;'; + put '%put NOTE- ;' /; + put 'deletefunc ' fileshort ';'; + isFunction + 1; + end; + put "run;" /; + + /* delete the link to the functions dataset */ + if isFunction then + do; + put 'options cmplib = (%unquote(%sysfunc(tranwrd(' / + '%lowcase(%sysfunc(getoption(cmplib)))' / + ',%str(' "work.%lowcase(&packageName.fcmp)" '), %str() ))));'; + put 'options cmplib = (%unquote(%sysfunc(compress(' / + '%sysfunc(getoption(cmplib))' / + ',%str(()) ))));'; + put '%put; %put NOTE:[CMPLIB] %sysfunc(getoption(cmplib));' /; + end; + + /* delete datasets */ + put "proc sql noprint;"; + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF; + if not (upcase(type)=:'DATA') then continue; + put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;'; + put '%put NOTE- ;' /; + put 'drop table ' fileshort ';'; + end; + put "quit;" /; + + /* delete libraries */ + EOF = 0; + do until(EOF); + set &filesWithCodes. end = EOF; + if not (upcase(type)=:'LIBNAME') then continue; + put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be cleared;'; + put '%put NOTE- ;' /; + put 'libname ' fileshort ' clear;'; + end; + put "run;" /; + + %if %bquote(&packageReqPackages.) ne %then + %do; + length packageReqPackages $ 32767; + packageReqPackages = lowcase(symget('packageReqPackages')); + /* try to load required packages */ + put 'data _null_ ; '; + put ' length req name $ 64; '; + put ' put "NOTE-" / "NOTE: To unload additional required SAS packages execute: " / "NOTE-"; '; + put ' do req = ' / packageReqPackages / ' ; '; + put ' name = strip(scan(req, 1, " ")); '; + put ' put ''NOTE- %unloadPackage( '' name ")" ; '; + put ' end ; '; + put ' put "NOTE-" / "NOTE-"; stop; '; + put 'run; '; + %end; + + + /* update SYSloadedPackages global macrovariable */ + put ' data _null_ ; '; + put ' length SYSloadedPackages $ 32767; '; + put ' if SYMEXIST("SYSloadedPackages") = 1 and SYMGLOBL("SYSloadedPackages") = 1 then '; + put ' do; '; + put ' do until(EOF); '; + put ' set sashelp.vmacro(where=(scope="GLOBAL" and name="SYSLOADEDPACKAGES")) end=EOF; '; + put ' substr(SYSloadedPackages, 1+offset, 200) = value; '; + put ' end; '; + put ' SYSloadedPackages = cats("#", translate(strip(SYSloadedPackages), "#", " "), "#"); '; + + put " if INDEX(lowcase(SYSloadedPackages), '#%lowcase(&packageName.)#') > 0 then "; + put ' do; '; + put " SYSloadedPackages = tranwrd(SYSloadedPackages, '#&packageName.#', '##'); "; + put ' SYSloadedPackages = compbl(translate(SYSloadedPackages, " ", "#")); '; + put ' call symputX("SYSloadedPackages", SYSloadedPackages, "G"); '; + put ' put "NOTE: " SYSloadedPackages = ; '; + put ' end ; '; + put ' end; '; + put ' stop; '; + put 'run; ' / ; + + + put '%put NOTE: '"Unloading package &packageName., version &packageVersion., license &packageLicense.;"; + put '%put NOTE- *** END ***;'; + put '%put NOTE- ;'; + + put "/* unload.sas end */"; + stop; +run; + +/* package help */ +data _null_; + /* break if no data */ + if NOBS = 0 then stop; + + file &zipReferrence.(help.sas); + length strX $ 32767; + + put "filename &_PackageFileref_. list;" /; + put ' %put NOTE- ;'; + put ' %put NOTE: '"Help for package &packageName., version &packageVersion., license &packageLicense.;"; + put ' %put NOTE: ' @; put "*** &packageTitle. ***; "; + put ' %put NOTE- ' @; put "Generated: %sysfunc(datetime(), datetime21.); "; + put ' %put NOTE- ' @; put "Author(s): &packageAuthor.; "; + put ' %put NOTE- ' @; put "Maintainer(s): &packageMaintainer.; "; + put ' %put NOTE- ;'; + put ' %put NOTE- *** START ***;' /; + + /* Use helpKeyword macrovariable to search for content (filename and type) */ + /* put '%local ls_tmp ps_tmp notes_tmp source_tmp; ';*/ + put '%let ls_tmp = %sysfunc(getoption(ls)); '; + put '%let ps_tmp = %sysfunc(getoption(ps)); '; + put '%let notes_tmp = %sysfunc(getoption(notes)); '; + put '%let source_tmp = %sysfunc(getoption(source)); '; + put 'options ls = MAX ps = MAX nonotes nosource; '; + put '%include' " &_PackageFileref_.(packagemetadata.sas) / nosource2; " /; + + put 'data _null_; '; + put ' if strip(symget("helpKeyword")) = " " then '; + put ' do until (EOF); '; + put " infile &_PackageFileref_.(description.sas) end = EOF; "; + put ' input; '; + put ' if upcase(strip(_infile_)) = "DESCRIPTION END:" then printer = 0; '; + put ' if printer then put "*> " _infile_; '; + put ' if upcase(strip(_infile_)) = "DESCRIPTION START:" then printer = 1; '; + put ' end; '; + put ' else stop; '; + put 'run; ' /; + + /* license info */ + put 'data _null_; '; + put ' if upcase(strip(symget("helpKeyword"))) = "LICENSE" then '; + put ' do until (EOF); '; + put " infile &_PackageFileref_.(license.sas) end = EOF; "; + put ' input; '; + put ' put "*> " _infile_; '; + put ' end; '; + put ' else stop; '; + put 'run; ' /; + + put 'data WORK._%sysfunc(datetime(), hex16.)_; '; + put 'infile cards4 dlm = "/"; '; + put 'input @; '; + put 'if 0 then output; '; + put 'length helpKeyword $ 64; '; + put 'retain helpKeyword "*"; '; + put 'drop helpKeyword; '; + put 'if _N_ = 1 then helpKeyword = strip(symget("helpKeyword")); '; + put 'if FIND(_INFILE_, helpKeyword, "it") or helpKeyword = "*" then '; + put ' do; '; + put ' input (folder order type file fileshort) (: $ 256.); '; + put ' output; '; + put ' end; '; + put 'cards4; '; + + EOFDS = 0; + do until(EOFDS); + /* content is created during package creation */ + set &filesWithCodes. end = EOFDS nobs = NOBS; + select; + when (upcase(type) = "DATA") fileshort2 = fileshort; + when (upcase(type) = "MACRO") fileshort2 = cats('%',fileshort,'()'); + when (upcase(type) = "FUNCTION") fileshort2 = cats(fileshort,'()'); + when (upcase(type) = "FORMAT") fileshort2 = cats('$',fileshort); + otherwise fileshort2 = fileshort; + end; + strX = catx('/', folder, order, type, file, fileshort, fileshort2); + put strX; + end; + + put ";;;;"; + put "run;" /; +/* + put 'proc print;'; + put 'run;'; +*/ + /* loop through content found and print info to the log */ + put 'data _null_; '; + put 'if upcase(strip(symget("helpKeyword"))) in (" " "LICENSE") then do; stop; end; '; + put 'if NOBS = 0 then do; ' / + 'put; put '' *> No help info found. Try %helpPackage(packageName,*) to display all.''; put; stop; ' / + 'end; '; + put ' do until(EOFDS); '; + put ' set WORK._last_ end = EOFDS nobs = NOBS; '; + put ' length memberX $ 1024; '; + put ' memberX = cats("_",folder,".",file); '; + /* inner datastep in call execute to read each embedded file */ + put ' call execute("data _null_; ");'; + put " call execute('infile &_PackageFileref_.(' || strip(memberX) || ') end = EOF; ');"; + put ' call execute(" printer = 0; ");'; + put ' call execute(" do until(EOF); ");'; + put ' call execute(" input; ");'; + put ' call execute(" if strip(_infile_) = cat(""/"",""*** "",""HELP END"","" ***"",""/"") then printer = 0; ");'; /* it looks like that because of comments */ + put ' call execute(" if printer then put ""*> "" _infile_; ");'; + put ' call execute(" if strip(_infile_) = cat(""/"",""*** "",""HELP START"","" ***"",""/"") then printer = 1; ");'; /* it looks like that because of comments */ + put ' call execute(" end; ");'; + put ' call execute(" put ""*> "" / ""*> ""; ");'; + put ' call execute(" stop; ");'; + put ' call execute("run; ");'; + put ' if lowcase(type) =: "data" then '; + put ' do; '; + put ' call execute("title ""Dataset " || strip(fileshort) || " from package &packageName. ""; ");'; + put ' call execute("proc contents data = " || strip(fileshort) || "; run; title; ");'; + put ' end; '; + /**/ + put " end; "; + put " stop; "; + put "run; "; + + /* cleanup */ + put "proc delete data = WORK._last_; "; + put "run; "; + put 'options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.; ' /; + + put '%put NOTE: '"Help for package &packageName., version &packageVersion., license &packageLicense.;"; + put '%put NOTE- *** END ***;' /; + put "/* help.sas end */"; + + stop; +run; + +/* create package content */ +data _null_; + /* break if no data */ + if NOBS = 0 then stop; + + set &filesWithCodes. nobs = NOBS; + + call execute(cat ('filename _IN_ "', catx('/', base, folder, file), '";')); + call execute(cats("filename _OUT_ ZIP '", base, "/%lowcase(&packageName.).zip' member='_", folder, ".", file, "';") ); + /* copy code file into the zip */ + call execute('data _null_;'); + call execute(' rc = fcopy("_IN_", "_OUT_");'); + call execute('run;'); + /* test file content for help tags */ + call execute('data _null_;'); + call execute(' retain test .;'); + call execute(' infile _IN_ lrecl=32767 dlm="0a0d"x end=EOF;'); + call execute(' input;'); + call execute(' if strip(_infile_) = cat("/","*** ","HELP START"," ***","/") then test + (+1); '); + call execute(' if strip(_infile_) = cat("/","*** ","HELP END", " ***","/") then test + (-1); '); + call execute(' if (test not in (.,0,1)) or (EOF and test) then '); + call execute(' do; '); + call execute(' put "ERR" "OR: unmatching or nested HELP tags!" _N_=; '); + call execute(' abort; '); + call execute(' end; '); + call execute(' if (EOF and test=.) then put "WARN" "ING: no HELP tags in the file." ; '); + call execute('run;'); + + call execute('filename _IN_ clear;'); + call execute('filename _OUT_ clear;'); +run; + +proc sql; + drop table &filesWithCodes.; +quit; +filename &zipReferrence. clear; +%mend generatePackage; + + +/* + +options mprint; +ods html; +%generatePackage( + testowyPackageName +,0.01 +,author +,contact +,filesLocation=E:\SAS_WORK_5400\testyGeneratePackage +) + +*/ + +/* +TODO: +- modyfikacja helpa, sprawdzanie kodu danje funkcji/makra/typu [v] + +- opcjonalne sortowanie nazw folderow(_) [v] + +- wewnętrzna nazwaz zmiennej z nazwa pakietu (na potrzeby kompilacji) [v] + +- weryfikacja srodaowiska + +- weryfikacja "niepustosci" obowiazkowych argumentow [v] + +- dodac typ "clear" do czyszczenia po plikach 'exec' [v] + +- doadc sprawdzanie liczby wywołan procedury fcmp, format i slowa '%macro(' w plikach z kodami [ ] + +- syspackages - makrozmienna z lista zaladowanych pakietow [v] as SYSloadedPackages + +- dodac typ "iml", "ds2", "proto" + +-lista wymaganych komponentow potrzebnych do działania SASa (na bazie proc SETINIT) [v] + +-sparwdzanie domknietosci, parzystosci i wystepowania tagow HELP START - HELP END w plikach [v] + +-weryfikacja nadpisywania makr [ ] + +-add MD5(&packageName.) value hash instead "package" word in filenames [v] + +-infolista o required packahes w unloadPackage [ ] +*/ + +/* + +%include "C:\SAS_PACKAGES\generatePackage.sas"; + +ods html; +%generatePackage(filesLocation=C:\SAS_PACKAGES\SQLinDS) +*/ + +/* +*"C:\SAS_PACKAGES\testyGeneratoraPakietow"; + +libname packages "E:\SAS_WORK_5400\testyGeneratePackage"; +filename packages "E:\SAS_WORK_5400\testyGeneratePackage"; + +%include packages(loadpackage.sas); + +dm 'log;clear'; +%loadpackage(testowypackagename) + + +*/ +/* + +%let helpKeyword=*; +%helpPackage(testowypackagename) +%unloadPackage(testowypackagename) + + +filename package ZIP "E:\SAS_WORK_5400\testyGeneratePackage\testowypackagename.zip"; + +%put %sysfunc(pathname(package)); + +%include package(load.sas); +%help()??? +%include package(unload.sas); + +filename package ZIP "C:\SAS_PACKAGES\testowypackagename.zip"; +%include package(load.sas); +%include package(unload.sas); + +filename package ZIP "C:\SAS_PACKAGES\macroarray.zip"; +%include package(load.sas); +%include package(unload.sas); +*/ diff --git a/macroarray.zip b/macroarray.zip index 9ce036c5310257078314a7bc954b4a4aa60bbd2f..ed98ab9699166eff30d1edc8fed3f66a941ee8b6 100644 GIT binary patch delta 4817 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 Rzamyp)@DM4RHlEn`9JQV^11*3 delta 4745 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 ZAFkqp^V0|6&-GdH>*iD>g(knn{{e*jdSd_p diff --git a/sqlinds.zip b/sqlinds.zip index da08a251fa80f51ed3e678622470ba28769c3162..573578da41265c5e5b349423012c7033e074879c 100644 GIT binary patch delta 4666 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 delta 4548 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 G@c#fo;dsvg