Compiling SAS SCL code programmatically - sas

Is there a programmatic way of compiling SAS 9.1.3 SCL code (N.B. not ordinary SAS code) in Windows? The only way I have found of doing it involves using the SAS GUI: we have a Perl script which sends keystrokes to the UI. While this works (sort of), it's ugly and error-prone, and is too fragile to add to our automated build script.
EDIT: My original question was probably somewhat unclear. I am aware of proc build; my problem is getting some plain text into the SAS catalogue as an SCL entry in the first place.

I found this to be a chicken-and-egg kind of problem. I found that it is only possible to get plain text into an SCL entry, by using an already existing SCL entry...
I have a setup, where I read and write SCL code in Catalog entries, from and to plain text files. I use this for revision control purposes (CVS).
While CVS is mostly used for plain text code, it can also handle binary files. Thus I have made an SCL entry (called FILE2SCL), that can import plain text into other SCL entries. I have then PROC CPORT'ed this SCL entry to a binary file, and checked it into CVS.
This way, I can always programmatically fetch this SCL entry from the CPORT file, and use this SCL entry to import SCL code from plain text into other SCL entries. Afterwards I can use PROC BUILD to compile the SCL entry, exactly like you mention yourself.
My FILE2SCL entry looks like this:
INIT:
/***************************************************************/
/* */
/* Call this SCL like this: */
/* %let srcFile=D:\work\dummy.scl; */
/* %let dstEntry=WORK.NEW.DUMMY.SCL; */
/* proc display catalog=work.cat.file2scl.scl; */
/* run; */
/* */
/***************************************************************/
length Rc 8;
length theFile $ 200;
length theEntry $ 128;
theFile=symget('SRCFILE'); * Source file *;
theEntry=symget('DSTENTRY'); * Destination entry *;
* Assign filename *;
Rc=filename('temp',theFile);
* Include external file into preview buffer *;
Rc=PREVIEW('INCLUDE','temp');
* Save contents of preview buffer to SCL entry *;
Rc=PREVIEW('SAVE',theEntry);
Rc=PREVIEW('CLEAR');
Rc=PREVIEW('CLOSE');
* Deassign filename *;
Rc=filename('temp','');
return;
The comment explains how to use it:
Start with setting a SAS macro variable, "srcFile", to contain the path to your SCL source code file, and another macro variable, "dstEntry" to contain the entry-path to where you want your SCL entry to be. Then PROC DISPLAY the FILE2SCL entry, and it will import your SCL source code into the specified SCL entry, and you can then compile it afterwards by using PROC BUILD.

Also, you can possibly check out using Eclipse and the ESLink plugin. It was designed specifically for this purpose (keeping SCL code in regular files for version control with the capability to compile into a catalog).

Related

Sas entreprise équivalent of x’cp …. …’

Is there an function which can copy a file from one folder to another one in sas enterprise? I know it’s the command cp in an Unix environment. I’m searching a solution which doesn’t make me change the default settings in sas.
Use the FCOPY() function.
Example from documentation:
/* Set MSGLEVEL to I to write messages from FCOPY to the log. */
options msglevel=i;
filename src 'source.txt';
filename dest 'destination.txt';
/* Create an example file to copy. */
data _null_;
file src;
do i=1, 2105, 300312, 400501;
put i:words256.;
end;
run;
/* Copy the records of SRC to DEST. */
data _null_;
length msg $ 384;
rc=fcopy('src', 'dest');
if rc=0 then
put 'Copied SRC to DEST.';
else do;
msg=sysmsg();
put rc= msg=;
end;
run;
If your SAS Session is locked down, you could try to use the RENAME() function.
If the SAS session in which you are specifying the FILEEXIST function is in a locked-down state, and the pathname specified in the function has not been added to the lockdown path list, then the function will fail and a file access error related to the locked-down data will not be generated in the SAS log unless you specify the SYSMSG function.
Don't get disturbed by the FILEEXIST, the documentation team forgot to change the function name when copy pasting the description...
data _null_;
rc = rename("\\path\to\file.csv",
"\\another\path\file.csv",
"file");
put rc=;
run;
If your platform administrator enabled the x command, you can just pass the command to your operating system.
x 'cp /from/path/data.file /to/path';
or with some typical macro variables
x "cp &fromPath/&dataFile &toPath";
Otherwise, it is impossible.

How to convert unicode to ebcdic CCSIDs-1025 and write to a db2

My problem is that the input is an XML file with UTF-8 encoding.
The database is encoded with CCSIDs-1025 (DB2).
The application itself is windows-1251 encoded.
After parsing the XML, I save the data to a regular char array. Of course, in my system there is no mapping for Unicode conversion and the array stores the correct byte representation, but something like this:
"RњRRќRR •R RЎRR'Rћ PYPyPPŽPP R R•RРRЈR'R›RRR R R•R›RR RRR€ RR™R†R"
It's not a problem.
I can convert it to windows-1251 and write it correctly to DB2 with ebcdic or work in my code.
But!
Is it possible to directly convert unicode to EBCDIC before writing to a table?
I Found one useful instrument ICU4C and tried to convert "Moscow" (Москва) to a EBCDIC CCSIDs-1025.
```lang-cpp
// CONVERTION USING ICU
UChar source[] = { 0x041C, 0x043E, 0x0441, 0x043A, 0x0432,
0x0430, 0x0021, 0x0000 };
char target[100];
UErrorCode status = U_ZERO_ERROR;
UConverter *conv;
int32_t len;
// set up the converter
//! [ucnv_open]
conv = ucnv_openCCSID(1154, UCNV_IBM, &status);
//! [ucnv_open]
assert(U_SUCCESS(status));
// convert to EBCDIC-1154.
len = ucnv_fromUChars(conv, target, 100, source, -1, &status);
assert(U_SUCCESS(status));
```
And again it converted correctly. And codes of symbols corresponds to a target CCSID.
\xCF \x9E \xAB \x9A \xAF \x77 \x4F - this is the result.
But how i can store result and insert it to a table with correct mapping?
It still takes symbols from windows-1251 (my application encoding) and "Москва" mapped as "ПћљЇwO". How can i said to DB2 to use characters from CCSIDs-1025.
Also i use embedded SQL and host variables in c++ application.
May be i need to set encoding of host variables during bind?
Thank you!
#Dastin_DV regarding your questions about CCSID for embedded SQL and host variables and the data encoding scheme your application handles, I'd like to explain it further here.
In Db2 for z/OS applications, one CCSID is associated with the source code and one or more CCSIDs can be associated with the data that your application manipulates. The CCSID that Db2 associates with the data is called the application encoding scheme.
There are a few general rules:
for application source code which includes SQL statements and literal strings in the SQL statements, if you are using the Db2 precompiler, use the CCSID SQL processing option when you precompile the application, specify the same CCSID when you compile the application; if you are using the Db2 coprocessor, use the language compiler to set the CCSID.
for application data, like values that are passed through host variables and parameter markers, within SQL statements, use one or more of the following Db2 mechanisms to set the CCSID value of the application data, which is called the application encoding scheme
use the ENCODING bind option.2.c This option typically yields the best performance.
override the CCSID for a particular host variable by using the DECLARE VARIABLE statement with the CCSID option.
override the CCSID for parameter markers in dynamic SQL by specifying the CURRENT APPLICATION ENCODING SCHEME special register. Db2 uses the value of this special register at the time that the statement is executed
for application data that is referenced outside of SQL statements, use the rules of the programming language, in some cases, the CCSID of this data is the same as the CCSID of the source code.

Combining GDAL dataset tiles in C++

I'm getting some prototype Python code that uses GDAL moved to C++ and I'm stuck on a section that reads tiles of elevation data from a directory and combines them into a single dataset. The Python code looks like:
# Read files containing elevation data in 1° x 1° squares.
geo_file_list = glob.glob ("./geodata/*.hgt")
# Turn the list of files into a list of datasets.
elv_dataset_list = list(map(gdal.Open, geo_file_list))
# Merge datasets into a single one.
elv_dataset = gdal.BuildVRT('', elv_dataset_list)
I'm never writing out the resulting VRT, only keeping it memory for further processing. I'd create a MEM driver and use that if possible.
In C++, I'm starting with:
// Set data directory.
std::string elev_dir = "./geodata/";
// Get list of files in data directory.
std::vector<GDALDataset *> elev_datasets;
// Read files into datasets.
for(auto& p: std::filesystem::directory_iterator(elev_dir)) {
elev_datasets.push_back((GDALDataset *) GDALOpen (p.path().c_str(), GA_ReadOnly));
}
The part I'm struggling with is sending the resulting std::vector to GDALBuildVRT(). Very possible that I'm going about this all wrong!
The trick was realizing that nullptr is an acceptable input into GDALBuildVRT() for arguments that should be ignored. Hence, the call looks like:
GDALDataset *dest_dataset = (GDALDataset *) GDALBuildVRT("", elev_datasets.size(), (GDALDatasetH *) elev_datasets.data(), nullptr, nullptr, nullptr);

Convert SAS7BCAT into DATASET

I try to open a SAS CATALOG file (SAS7BCAT) with SAS ENTERPRISE GUIDE. And I receive always this message :
ERROR: File DIFTFMT.FORMATSX64.CATALOG was created for a different
operating system.
Who could convert my CATALOG format in a DATASET format? Like this I will be able to create my own catalog!
Thank you in advance.
For your information : The operating system used to create this CATALOG file is 9.0401B0X64_S08R2
The code which retunrs the error :
/* SAS CODE BEGIN*/
libname diftfmt '/ec/local/sas/data/training/OrionStar/orfmt';
options fmtsearch=(diftfmt);
PROC FORMAT library=diftfmt.formatsx64 fmtlib;
RUN;
/* SAS CODE END*/
The code to find the operating system:
/* SAS CODE BEGIN*/
filename test
"/ec/local/sas/data/training/OrionStar/orfmt/formatsx64.sas7bcat";
DATA enc (keep=encoding);
length encoding $ 20;
infile test truncover scanover;
input #'9.0' enc $14.;
encoding = '9.0' || enc;
RUN;
/* SAS CODE END*/

SAS Compare Two Text Files (Unix / Windows)

I need to compare two text files (in different directories) to see if they are different (a binary result is fine). Given a dataset such as the one below, is this possible within a datastep?
Pathname
c:\one\text1.txt
c:\two\text1.txt
c:\one\text2.txt
c:\two\text2.txt
Alternatively, macro code would be fine! Checksum is a possibility, I need the code to run in both windows & unix.
Pass it to the command line (via a pipe fileref)
In Windows, use the 'comp' command.
In Unix, use the 'diff' command.
Thanks to Chris J - this worked for me:
%let root=%sysfunc(pathname(work));
data;
file "&root.\x.txt";
put 'xxx';
data;
file "&root.\x2.txt";
put 'xx x';
filename x pipe "diff &root.\x.txt &root.\x2.txt ";
data;
infile x;
input x $1000.;
run;