![]() | ![]() | ![]() | ![]() | ![]() |
If you attempt to use PROC CPORT to convert a SAS Version 5 format, PROC CPORT fails and displays the following error message in the SAS log:
ERROR: Library SASLIB is not in a valid format for access method SASE7. NOTE: The SAS System stopped processing this step because of errors.
The V5TOV6 procedure is the correct procedure to use to convert a SAS Version 5 format library to SAS® 6.09. You can then use SAS 6.09 to create a transport file that can be imported into any release of SAS.
To work around the need to load SAS 6.09 and run the V5TOV6 procedure, you can convert your SAS Version 5 format library in one step instead of two in SAS 8 or SAS 9 using the program that is available for download on the Downloads tab. The program is effectively equivalent to the V5TOV6 migration procedure, although the only functionality provided by the %CONVERT_FMTLIB macro is for the conversion of formats (PROC V5TOV6 converts other entities as well).
Click the Output tab to see an example of the SAS log that is produced by the %CONVERT_FMTLIB macro.
If you have SAS 6.09 and want the syntax to run the V5TOV6 procedure, see SAS Note 17182, "The error "Library SASLIB is not in a valid format for access method SASE7" might be generated when you write to a format library."
| Product Family | Product | System | SAS Release | |
| Reported | Fixed* | |||
| SAS System | Base SAS | z/OS | 8.1 TS1M0 | |
Below is an example of the SAS log produced by the %CONVERT_FMTLIB macro.
1 filename saslibx "SASCTP.V5.FMTEST" lrecl=32760 blksize=32760;
2
3 /*-----------------------------------------------------------------*/
4 /* This macro will read an entire load module PDS, extracting out */
5 /* all the old-style formats (ones generated by PROC FORMAT). */
6 /* The members of the PDS must have an SSI starting with AE to be */
7 /* a format. It is possible that formats in assembler, not created */
8 /* by PROC FORMAT, will be present, but those cannot be processed. */
9 /* */
10 /* %convert_fmtlib(v5fmtlib=SASLIBX, cntlin=CNTLIN, fmtlib=work, */
11 /* fmtcat=FORMATS */
12 /* */
13 /* where */
14 /* */
15 /* cntlin the name of the cntlin data set to create */
16 /* ddname the DDname for the load module PDS */
17 /* */
18 /* Once the cntlin data set is created, it can be run through PROC */
19 /* FORMAT using the CNTLIN= option. */
20 /* */
21 /* Note that this macro is effectively equivalent to the V5TOV6 */
22 /* migration procedure that was available in SAS Version 6, */
23 /* although the only functionality provided by this macro is for */
24 /* conversion of formats. (V5TOV6 converted other entities as */
25 /* well). */
26 /* */
27 /* This macro can be run using Version 8 of the SAS System or */
28 /* higher. */
29 /*-----------------------------------------------------------------*/
30
31 %macro convert_fmtlib(v5fmtlib=SASLIBX,cntlin=CNTLIN,fmtlib=WORK,
32 fmtcat=FORMATS);
33 %put %str(************************************************************)
33 ! ;
34 %put %str(* Converting old V5 format library allocated to DDNAME: )
34 ! ;
35 %put %str(* &V5FMTLIB )
35 ! ;
36 %put %str(* )
36 ! ;
37 %put %str(* These converted formats will be written to: )
37 ! ;
38 %put %str(* &FMTLIB..&FMTCAT )
38 ! ;
39 %put %str(************************************************************)
39 ! ;
40
41 %let v5fmtlibrc=%sysfunc(fexist(&v5fmtlib));
42 %if &v5fmtlibrc eq %str(0) %then
43 %do;
44 %put ***************************************************************;
45 %put ERROR: You must pre-allocate the V5 format library.;
46 %put NOTE: You can do this with a FILENAME statement or externally.;
47 %put NOTE: Default fileref/DDname is SASLIBX.;
48 %put NOTE: To tell this routine the fileref use V5FMTLIB= keyword.;
49 %put ***************************************************************;
50 %put;
51 %put;
52 %put ***************************************************************;
53 %put Syntax to invoke this routine is:;
54 %put;
55 %put CONVERT_FMTLIB(V5FMTLIB=saslibx,FMTLIB=work,FMTCAT=library);
56 %put;
57 %put V5FMTLIB= (required) fileref/DDname of V5 format library.;
58 %put Must be preallocated before invoking this macro;
59 %put Default value: SASLIBX;
60 %put FMTLIB= (required) libref/DDname of SAS library for formats.;
61 %put Must be preallocated before invoking this macro;
62 %put Default value: WORK;
63 %put FMTCAT= (optional) format catalog name to store formats;
64 %put Default value: FORMATS;
65 %put;
66 %put ***************************************************************;
67 %end;
68 %else
69 %do;
70 /*-----------------------------------------------------------------*/
71 /* First create a template cntlin data set that will contain all */
72 /* the necessary variables with the desired lengths. The start */
73 /* and end values have a max of 16 in old-style formats, and the */
74 /* labels have a max of 40. Format names have a max of 8. This */
75 /* data set will have no observations, but will be used as the */
76 /* BASE= data set for PROC APPEND, so we can be sure that the */
77 /* proper lengths are maintained. */
78 /*-----------------------------------------------------------------*/
79 data &cntlin;
80 length fmtname $8 type $1 start end $16 label $40 hlo $8
81 sexcl eexcl $1
82 mult 8 prefix $2 fill $1
83 min max default noedit 4;
84 retain fmtname ' ' type ' ' start ' ' end ' ' label ' '
85 hlo ' ' sexcl ' ' eexcl ' ' prefix ' ' fill ' '
86 mult . min . max . default . noedit .;
87 delete;
88 run;
89
90 /*-----------------------------------------------------------------*/
91 /* The FILEEXT=ASIS option needs to be specified here. This option */
92 /* allows for memnames that have atypical characters to be */
93 /* processed properly. The character of concern is an underscore, */
94 /* which is valid in a format name. Without this option, the name */
95 /* would be translated to use # when accessed in the DATA step, */
96 /* and this would fail since the memname with a # would not be */
97 /* found. */
98 /*-----------------------------------------------------------------*/
99
100 options fileext=asis;
101
102 /*-----------------------------------------------------------------*/
103 /* All the members are read from the directory blocks of the PDS. */
104 /* Using LRECL=256 BLKSIZE=256 allows the directory to be read */
105 /* instead. We are only interested in the member name and the SSI */
106 /* field, and we are only interested in those members with an SSI */
107 /* starting with AE, which indicates a format. */
108 /*-----------------------------------------------------------------*/
109
110 %let found_underscore=0;
111 data memlist; infile &v5fmtlib recfm=u lrecl=256 blksize=256;
112 retain mwritten 0;
113 keep memname ssi;
114 input @3 @;
115 do i=1 to 6;
116 input memname $char8. +26 ssi $char4. +2 @;
117 if substr(ssi,1,1) NE 'AE'x then continue;
118 if memname='ffffffffffffffff'x then stop;
119 j = index(memname,'_');
120 if j then do;
121 ***** memname=translate(memname,'#','_');
122 if NOT mwritten then call symput('found_underscore','1');
123 mwritten=1;
124 end;
125 output;
126 end;
127 run;
128
129 /*-----------------------------------------------------------------*/
130 /* The following code is no longer used, but left in, in case it */
131 /* may later be needed. Without the FILEEXT=ASIS option, the PDS */
132 /* needs to be copied to a temporary location where the memnames */
133 /* containing underscores can be changed to use # instead. This */
134 /* code uses PDSCOPY to copy the PDS to TEMPFIL1, using the */
135 /* OUTTAPE option so it's a sequential stream. TEMPFIL1 is copied */
136 /* to TEMPFIL2, but with all the records referencing the members */
137 /* being updated to change _ to #. Then PDSCOPY recreates the */
138 /* PDS in TEMPPDS, and that PDS is then subsequently used. */
139 /*-----------------------------------------------------------------*/
140 /*
141 %if &found_underscore %then %do;
142 filename tempfil1 temp;
143 filename tempfil2 temp;
144 filename temppds temp dsorg=po;
145 proc pdscopy dc indd=&v5fmtlib. outdd=tempfil1 outtape; run;
146 data _null_; infile tempfil1; file tempfil2 dcb=tempfil1;
147 input @;
148 c=substr(_infile_,1,1);
149 length memname $8;
150 if c='H' then do;
151 memname=substr(_infile_,11,8);
152 i=index(memname,'_');
153 if i then substr(_infile_,11+i-1,1)='#';
154 end;
155 else if c='D' then do;
156 memname=substr(_infile_,19,8);
157 i=index(memname,'_');
158 if i then substr(_infile_,19+i-1,1)='#';
159 end;
160 put _infile_;
161 run;
162 proc pdscopy indd=tempfil2 outdd=temppds intape; run;
163 filename tempfil1 clear;
164 filename tempfil2 clear;
165 %let v5fmtlib=TEMPPDS;
166 %end;
167 */
168
169 /*-----------------------------------------------------------------*/
170 /* Here the list of members is run through, and the %readmem */
171 /* macro is invoked for each member via CALL EXECUTE. */
172 /*-----------------------------------------------------------------*/
173
174 data _null_; set memlist;
175 length command $200;
176 command='%readmem('
177 ||"&cntlin.,"
178 ||"&v5fmtlib.,"
179 || memname||','
180 ||put(ssi,$hex8.)
181 ||');';
182 call execute(trim(command));
183 run;
184
185 /*-----------------------------------------------------------------*/
186 /* Clean up after ourselves. */
187 /*-----------------------------------------------------------------*/
188
189 proc delete data=memlist; run;
190
191 /*
192 %if &found_underscore %then %do;
193 filename temppds clear;
194 %end;
195 */
196
197 %end;
198 %mend convert_fmtlib;
199
200 /*-----------------------------------------------------------------*/
201 /* This macro will read a member of a load module PDS, expecting */
202 /* it to be an old-style format (one generated by PROC FORMAT). */
203 /* It will extract the ranges and labels from this load module */
204 /* member, and append to a CNTLIN data set the range/label pairs */
205 /* defined in the format. */
206 /* */
207 /* %readmem(cntlin,ddname,memname,ssi); */
208 /* */
209 /* where */
210 /* */
211 /* cntlin the name of the cntlin data set to append to */
212 /* ddname the DDname for the load module PDS */
213 /* memname the member name to be processed */
214 /* ssi the SSI in hex (should start with AE) */
215 /*-----------------------------------------------------------------*/
216
217 %macro readmem(cntlin,v5fmtlib,memname,ssi);
218 data header(keep=fmtname type min max default)
219 ranges(keep=start end labelnum hlo sexcl eexcl )
220 labels(keep=labelnum label mult prefix noedit fill);
221 infile &v5fmtlib(&memname) column=c length=l;
222 length fmtname $8 type $1 start end $16 label $40 hlo $8
223 sexcl eexcl $1
224 mult 8 prefix $2 fill $1
225 min max default noedit 4;
226
227 length buffer $200;
228
229 /*-------------------------------------------------------------*/
230 /* The memname starts with @ if an informat is defined. The */
231 /* memname has a $ if it is a character format. The TYPE */
232 /* variable should be set as: N=numeric C=character */
233 /* I=numeric informat J=character informat. Note that TYPE */
234 /* should be set to P for PICTURE formats, but we won't know */
235 /* for sure that we have a PICTURE format until later. */
236 /*-------------------------------------------------------------*/
237
238 fmtname=translate("&memname.",'_','#');
239 if fmtname=:'@' then do;
240 fmtname=substr(fmtname,2);
241 if fmtname=:'$' then type='J'; else type='I';
242 end;
243 else do;
244 if fmtname=:'$' then type='C'; else type='N';
245 end;
246
247 /*-------------------------------------------------------------*/
248 /* SSI: AElhhdrw l=min hh=max w*16+d=default */
249 /* r=0 left just, 8=right just */
250 /*-------------------------------------------------------------*/
251
252 min=input(substr("&ssi.",3,1),hex1.);
253 max=input(substr("&ssi.",4,2),hex2.);
254 default=input(substr("&ssi.",8,1),hex2.)*16+
255 input(substr("&ssi.",6,1),hex1.);
256
257 /*-------------------------------------------------------------*/
258 /* All formats have a LH R8,Rnnn instruction, and the nnn is */
259 /* the offset into the module where the ranges begin. The */
260 /* binary for LH R8 is 4880. We search for this to begin the */
261 /* process. Note that if this isn't found, we end up at EOF */
262 /* and the header/ranges/labels data sets have no observations.*/
263 /* The offset needs to have the register nibble cleared out. */
264 /*-------------------------------------------------------------*/
265
266 input @'4880'x @;
267 input offset pib2. @;
268 offset=band(offset,0fffx);
269
270 /*-------------------------------------------------------------*/
271 /* In V5, the type character N|C|P was added at offset 20, */
272 /* for Numeric|Character|Picture. */
273 /* If it's there and it's a P, we know we have a PICTURE */
274 /* format. */
275 /*-------------------------------------------------------------*/
276
277 input @20 ncp $char1. @;
278 picfmt=(ncp='P');
279
280 /*-------------------------------------------------------------*/
281 /* We head to the offset and get the range count, the length */
282 /* of the labels, and the bits byte. We can determine OTHER, */
283 /* UPCASE, JUST, and whether it is a 76.5 or 76.6 format. If */
284 /* a numeric format, the we read the FUZZ value. */
285 /*-------------------------------------------------------------*/
286
287 input @1 +offset fmt_count pib2. bits pib1. fmt_length pib1. @;
288 other=^^band(bits,080x);
289 upcase=^^band(bits,010x);
290 just=^^band(bits,040x);
291 fmt765 = (offset = 292);
292 fmt766 = (offset = 312);
293 charfmt=(type^='N');
294 if ^charfmt then input fuzz rb4. @;
295 if upcase then hlo='U';
296 if just then hlo=trim(hlo)||'J';
297
298 /*-------------------------------------------------------------*/
299 /* If an OTHER= clause was given, then we emit a range for */
300 /* that. It will always be the first one with LABELNUM=1. */
301 /* HLO is set for this observation only to have O in it for */
302 /* OTHER. START and END are set to **OTHER**. */
303 /*-------------------------------------------------------------*/
304
305 if other then do;
306 start='**OTHER**'; end=start; labelnum=1;
307 hlo=trim(hlo)||'O';
308 output ranges;
309 substr(hlo,length(hlo),1)=' ';
310 end;
311
312 /*-------------------------------------------------------------*/
313 /* Note that all subsequent access of data from the load */
314 /* module is done via the readbytes link routine. This is */
315 /* because our data can span multiple records, and readbytes */
316 /* ensures an intact buffer to process. */
317 /*-------------------------------------------------------------*/
318
319 /*-------------------------------------------------------------*/
320 /* Read through all the ranges and output to the ranges data */
321 /* set. */
322 /*-------------------------------------------------------------*/
323
324 nlabels=0;
325 do j=1 to fmt_count;
326
327 /*----------------------------------------------------------*/
328 /* The old 76.5 numeric formats have 2 8-byte doubles */
329 /* followed by a long integer subscript. */
330 /*----------------------------------------------------------*/
331
332 if fmt765 then do;
333 len=20; link readbytes;
334 start=substr(buffer,1,8);
335 end=substr(buffer,9,8);
336 sub=input(substr(buffer,17,4),pib4.);
337 x='00'x;
338 end;
339
340 /*----------------------------------------------------------*/
341 /* Character formats have 16-byte strings for start and */
342 /* end and a short subscript. If the string is all '00'x */
343 /* then it is LOW, if all 'FF'x it is HIGH. */
344 /*----------------------------------------------------------*/
345
346 else if charfmt then do;
347 len=36; link readbytes;
348 start=substr(buffer,1,16);
349 end=substr(buffer,17,16);
350 x=substr(buffer,33,1);
351 sub=input(substr(buffer,35,2),pib2.);
352 low=(verify(substr(start,1,16),'00'x)=0);
353 high=(verify(substr(end,1,16),'FF'x)=0);
354 end;
355
356 /*----------------------------------------------------------*/
357 /* Numeric formats have 2 8-byte doubles and a long integer */
358 /* subscript. */
359 /*----------------------------------------------------------*/
360
361 else do;
362 len=24; link readbytes;
363 start=substr(buffer,1,8);
364 end=substr(buffer,9,8);
365 sub=input(substr(buffer,17,4),pib4.);
366 x=substr(buffer,18,1);
367 end;
368
369 /*----------------------------------------------------------*/
370 /* Compute the label number and keep up with the highest */
371 /* number, since that is the only way we know the number of */
372 /* labels. */
373 /*----------------------------------------------------------*/
374
375 labelnum = sub - ^other;
376 nlabels=max(nlabels,labelnum);
377
378 sexcl=' '; eexcl=' ';
379
380 /*----------------------------------------------------------*/
381 /* For numeric formats, a missing value can be represented */
382 /* by 'FF'x in the first byte, and the missing value */
383 /* character in the last byte. We adjust it back. If the */
384 /* value is '8000000000000001'x then this indicates an */
385 /* exclusion, so we set SEXCL or EEXCL to Y accordingly. */
386 /* START/END are then informatted using RB8. to the number */
387 /* wanted, which is the formatted out using BEST16. for */
388 /* the CNTLIN data set. */
389 /*----------------------------------------------------------*/
390
391 if ^charfmt then do;
392 if substr(start,1,1)='FF'x
393 then substr(start,1,1)=substr(start,2,1);
394 if substr(start,1,8)='8000000000000001'x then do;
395 start='0000000000000000'x;
396 sexcl='Y';
397 end;
398 start=left(put(input(substr(buffer,1,8),rb8.),best16.));
399 if substr(end,1,8)='8000000000000001'x then do;
400 end='0000000000000000'x;
401 eexcl='Y';
402 end;
403 else if substr(end,1,1)='FF'x
404 then substr(end,1,1)=substr(end,2,1);
405 end= left(put(input(substr(buffer,9,8),rb8.),best16.));
406 low=(substr(start,1,8)='FEFFFFFFFFFFFFFF'x);
407 high=(substr(end,1,8)='7FFFFFFFFFFFFFFF'x);
408 end;
409
410 /*----------------------------------------------------------*/
411 /* If SEXCL and EEXCL aren't yet set, the exclusion bits */
412 /* tell us if they need to be set. */
413 /*----------------------------------------------------------*/
414
415 if sexcl=' ' then do;
416 if band(input(x,pib1.),80x) then sexcl='Y'; else sexcl='N';
417 end;
418 if eexcl=' ' then do;
419 if band(input(x,pib1.),40x) then eexcl='Y'; else eexcl='N';
420 end;
421
422 /*----------------------------------------------------------*/
423 /* Set L and H for low and high in HLO if LOW or HIGH */
424 /* values were specified. */
425 /*----------------------------------------------------------*/
426
427 if low then do;
428 start='**LOW**';
429 hlo=trim(hlo)||'L';
430 end;
431 if high then do;
432 end='**HIGH**';
433 hlo=trim(hlo)||'H';
434 end;
435
436 /*----------------------------------------------------------*/
437 /* Output our range, and reset HLO so that L and H are */
438 /* no longer there. */
439 /*----------------------------------------------------------*/
440
441 output ranges;
442 hlo=compress(hlo,'LH');
443 end;
444
445 /*-------------------------------------------------------------*/
446 /* At this point all the ranges have been read and we are at */
447 /* the label section. There is a dummy label inserted if there */
448 /* no OTHER= clause. It is skipped here. Then we loop through */
449 /* and read the labels. Note that the label count has been */
450 /* determined to be nlabels, but not if we had OTHER= only, so */
451 /* we ensure nlabels is set accordingly. */
452 /*-------------------------------------------------------------*/
453
454 if ^other then do;
455 len=fmt_length; link readbytes;
456 end;
457 else nlabels=max(nlabels,other);
458
459 do labelnum=1 to nlabels;
460
461 /*----------------------------------------------------------*/
462 /* Read our buffer containing the label. */
463 /*----------------------------------------------------------*/
464
465 len=fmt_length; link readbytes;
466
467 /*----------------------------------------------------------*/
468 /* If it's the first label, and it could be PICTURE but we */
469 /* haven't determined for sure, we can check now and see */
470 /* if the first 2 bytes of the label are a short integer */
471 /* between 1 and 24. If so, we assume we have a PICTURE */
472 /* format. Note that this would apply to PICTURE formats */
473 /* in 76.6, SAS79, and SAS82. The length is always 40 with */
474 /* these PICTURE formats. In V5, PICTURE was specified in */
475 /* the header so this check is not necessary. */
476 /*----------------------------------------------------------*/
477
478 if labelnum=1 and ^fmt765 and ^charfmt and
479 fmt_length=40 and ^picfmt then do;
480 picfmt = 1<=input(substr(buffer,1,2),ib2.)<=24;
481 end;
482
483 /*----------------------------------------------------------*/
484 /* For PICTURE formats, we extract the various fields. The */
485 /* digit selectors are '20'X for 0 and '21'X for 1. */
486 /*----------------------------------------------------------*/
487
488 if picfmt then do;
489 mult=input(substr(buffer,5,8),rb8.);
490 prefix=substr(buffer,13,2);
491 noedit=(substr(buffer,15,1)='01'x);
492 fill=substr(buffer,16,1);
493 label=substr(buffer,17,24);
494 if ^noedit
495 then label=translate(label,'09','2021'x);
496 end;
497
498 /*----------------------------------------------------------*/
499 /* The label is copied as is for non-PICTURE labels. */
500 /*----------------------------------------------------------*/
501 else do;
502 label=substr(buffer,1,fmt_length);
503 end;
504
505 output labels;
506 end;
507
508 /*-------------------------------------------------------------*/
509 /* The single header observation can be emitted now that we */
510 /* know for sure if we have a PICTURE format. */
511 /*-------------------------------------------------------------*/
512
513 if picfmt then type='P';
514 output header;
515 stop;
516 return;
517
518 /*-----------------------------------------------------------------*/
519 /* This link routine will read bytes from the load module. len will*/
520 /* be the number of bytes wanted. l is the length from the LENGTH= */
521 /* option and c is the column from the COLUMN= option. We simply */
522 /* read bytes into the buffer if we have them all. Otherwise we */
523 /* read a byte at a time until we fill the buffer, going to new */
524 /* records as needed. Note that records of length 20 are considered*/
525 /* to be continuation records and are ignored. */
526 /*-----------------------------------------------------------------*/
527
528 readbytes:;
529 left=l-c+1;
530 if left>=len then do;
531 input buffer $varying200. len @;
532 end;
533 else do ii=1 to len;
534 if c>l then do;
535 input / @;
536 if l=20 then input / @;
537 end;
538 input byte $char1. @;
539 substr(buffer,ii,1)=byte;
540 end;
541 return;
542 run;
543
544 /*-----------------------------------------------------------------*/
545 /* The ranges will be in sorted order by range, and not necessarily*/
546 /* in sorted order for the labels, so we sort by label number so */
547 /* we can merge with the labels. */
548 /*-----------------------------------------------------------------*/
549
550 proc sort data=ranges; by labelnum;
551 run;
552
553 /*-----------------------------------------------------------------*/
554 /* Create our CNTLIN data set from the 3 data sets. */
555 /*-----------------------------------------------------------------*/
556
557 data cntlinx; merge ranges labels; by labelnum;
558 if _n_=1 then set header;
559 drop labelnum;
560 run;
561
562 /*-----------------------------------------------------------------*/
563 /* Append to the final CNTLIN data set and clean up. */
564 /*-----------------------------------------------------------------*/
565
566 proc append base=&cntlin data=cntlinx;
567 run;
568 proc delete data=header ranges labels cntlinx;
569 run;
570
571 /*-----------------------------------------------------------------*/
572 /* Added ability to create user formats to specified library RHA */
573 /* defaults to WORK.LIBRARY RHA */
574 /* Added FMTLIB option to PROC FORMAT statement JLG */
575 /*-----------------------------------------------------------------*/
576 proc format cntlin=&cntlin fmtlib library=&fmtlib..&fmtcat.; run;
577 %mend readmem;
578
579
580 /*----------------------------------------------------------------*/
581 /* CALL MACRO; Modify parameter list or take defaults */
582 /*----------------------------------------------------------------*/
583 %convert_fmtlib(v5fmtlib=SASLIBX, cntlin=CNTLIN, fmtlib=WORK,
584 fmtcat=formats)
************************************************************
* Converting old V5 format library allocated to DDNAME:
* SASLIBX
*
* These converted formats will be written to:
* WORK.formats
************************************************************
NOTE: The data set WORK.CNTLIN has 0 observations and 15 variables.
NOTE: The DATA statement used 0.01 CPU seconds and 18916K.
NOTE: The address space has used a maximum of 660K below the line and
19872K above the line.
NOTE: The infile SASLIBX is:
Dsname=SASCTP.V5.FMTEST,
Unit=3390,Volume=SAS902,Disp=SHR,Blksize=256,
Lrecl=256,Recfm=U,Creation=1997/09/30
NOTE: 2 records were read from the infile SASLIBX.
The minimum record length was 256.
The maximum record length was 256.
NOTE: The data set WORK.MEMLIST has 1 observations and 2 variables.
NOTE: The DATA statement used 0.01 CPU seconds and 18964K.
NOTE: The address space has used a maximum of 660K below the line and
19924K above the line.
NOTE: There were 1 observations read from the data set WORK.MEMLIST.
NOTE: The DATA statement used 0.01 CPU seconds and 19107K.
NOTE: The address space has used a maximum of 660K below the line and
20068K above the line.
NOTE: CALL EXECUTE generated line.
1 + data header(keep=fmtname type min max default) ranges(keep=start
end labelnum hlo sexcl eexcl ) labels(keep=labelnum label mult prefix
noedit fill); infile SASLIBX(TEMP) column=c length=l; length
fmtname $8 type $1 start end $16 label
2 + $40 hlo $8 sexcl eexcl $1 mult 8 prefix $2
fill $1 min max default noedit 4; length buffer $200;
fmtname=translate("TEMP",'_','#'); if fmtname=:'@' then
3 + do; fmtname=substr(fmtname,2); if fmtname=:'$' then
type='J'; else type='I'; end; else do; if fmtname=:'$'
then type='C'; else type='N'; end;
min=input(substr("AE428400",3,1
4 +),hex1.); max=input(substr("AE428400",4,2),hex2.);
default=input(substr("AE428400",8,1),hex2.)*16+
input(substr("AE428400",6,1),hex1.);
input @'4880'x @; input offset pib2.
5 + @; offset=band(offset,0fffx);
input @20 ncp $char1. @; picfmt=(ncp='P');
input @1 +offset fmt_count pib2. bits pib1.
fmt_length pib1. @; other=^^band
6 +(bits,080x); upcase=^^band(bits,010x);
just=^^band(bits,040x); fmt765 = (offset = 292); fmt766 = (offset
= 312); charfmt=(type^='N'); if ^charfmt then input fuzz rb4. @;
if upcase then hlo='U'; if just then hlo=trim
7 +(hlo)||'J'; if other then
do; start='**OTHER**'; end=start; labelnum=1;
hlo=trim(hlo)||'O'; output ranges;
substr(hlo,length(hlo),1)=' '; end;
8 + nlabels=0; do j=1 to
fmt_count; if fmt765 then do;
len=20; link readbytes; start=substr(buffer,1,8);
end=substr(buffer,9,8);
9 + sub=input(substr(buffer,17,4),pib4.); x='00'x;
end; else if
charfmt then do; len=36; link readbytes;
start=substr(buffer,1,16); end=substr
10 +(buffer,17,16); x=substr(buffer,33,1);
sub=input(substr(buffer,35,2),pib2.);
low=(verify(substr(start,1,16),'00'x)=0);
high=(verify(substr(end,1,16),'FF'x)=0); end;
11 + else do; len=24; link readbytes;
start=substr(buffer,1,8); end=substr(buffer,9,8);
sub=input(substr(buffer,17,4),pib4.); x=substr(buffer,18,1);
end;
12 + labelnum = sub - ^other;
nlabels=max(nlabels,labelnum); sexcl=' '; eexcl=' ';
if ^charfmt then do; if
13 + substr(start,1,1)='FF'x then
substr(start,1,1)=substr(start,2,1); if
substr(start,1,8)='8000000000000001'x then do;
start='0000000000000000'x; sexcl='Y'; end;
start=left(put
14 +(input(substr(buffer,1,8),rb8.),best16.)); if
substr(end,1,8)='8000000000000001'x then do;
end='0000000000000000'x; eexcl='Y'; end;
else if substr(end,1,1)='FF'x then substr
15 +(end,1,1)=substr(end,2,1); end=
left(put(input(substr(buffer,9,8),rb8.),best16.));
low=(substr(start,1,8)='FEFFFFFFFFFFFFFF'x);
high=(substr(end,1,8)='7FFFFFFFFFFFFFFF'x); end;
16 + if sexcl=' ' then do; if
band(input(x,pib1.),80x) then sexcl='Y'; else sexcl='N'; end;
if eexcl=' ' then do; if band(input(x,pib1.),40x) then
eexcl='Y'; else eexcl='N'; end;
17 + if low then do;
start='**LOW**'; hlo=trim(hlo)||'L'; end; if
high then do; end='**HIGH**'; hlo=trim(hlo)||'H';
end;
18 + output ranges; hlo=compress(hlo,'LH'); end;
if ^other then do;
len=fmt_length; link readbytes; end; else
nlabels=max(nlabels,other); do labelnum=1
19 + to nlabels; len=fmt_length; link
readbytes;
if labelnum=1 and ^fmt765 and ^charfmt
and fmt_length=40 and
20 + ^picfmt then do; picfmt =
1<=input(substr(buffer,1,2),ib2.)<=24; end;
if picfmt then do;
mult=input(substr(buffer,5,8),rb8.); prefix=substr(buffer,13,2);
21 + noedit=(substr(buffer,15,1)='01'x);
fill=substr(buffer,16,1); label=substr(buffer,17,24);
if ^noedit then label=translate(label,'09','2021'x);
end; else do;
22 + label=substr(buffer,1,fmt_length); end;
output labels; end; if picfmt then
type='P'; output header; stop; return;
readbytes:; left=l-c+1; if
23 + left>=len then do; input buffer $varying200. len @;
end; else do ii=1 to len; if c>l then do; input /
@; if l=20 then input / @; end; input byte
$char1. @; substr(buffer,ii,1
24 +)=byte; end; return; run;
NOTE: The infile library SASLIBX is:
Dsname=SASCTP.V5.FMTEST,
Unit=3390,Volume=SAS902,Disp=SHR,Blksize=32760,
Lrecl=32760,Recfm=U,Creation=2010/11/03
NOTE: The infile SASLIBX(TEMP) is:
Dsname=SASCTP.V5.FMTEST(TEMP),
Unit=3390,Volume=SAS902,Disp=SHR,Blksize=32760,
Lrecl=32760,Recfm=U,Creation=2010/11/03
NOTE: A total of 3 records were read from the infile library SASLIBX.
The minimum record length was 20.
The maximum record length was 512.
NOTE: 3 records were read from the infile SASLIBX(TEMP).
The minimum record length was 20.
The maximum record length was 512.
NOTE: SAS went to a new line when INPUT @'CHARACTER_STRING' scanned past
the end of a line.
NOTE: The data set WORK.HEADER has 1 observations and 5 variables.
NOTE: The data set WORK.RANGES has 1 observations and 6 variables.
NOTE: The data set WORK.LABELS has 1 observations and 6 variables.
NOTE: The DATA statement used 0.02 CPU seconds and 19791K.
NOTE: The address space has used a maximum of 660K below the line and
20756K above the line.
24 + proc sort
data=ranges; by labelnum; run; data cntlinx; merge
ranges labels; by labelnum; if _n_=1 then set header; drop
labelnum; run; proc append base=CNTLIN
NOTE: There were 1 observations read from the data set WORK.RANGES.
NOTE: The data set WORK.RANGES has 1 observations and 6 variables.
NOTE: The PROCEDURE SORT used 0.00 CPU seconds and 20194K.
NOTE: The address space has used a maximum of 660K below the line and
21176K above the line.
NOTE: There were 1 observations read from the data set WORK.RANGES.
NOTE: There were 1 observations read from the data set WORK.LABELS.
NOTE: There were 1 observations read from the data set WORK.HEADER.
NOTE: The data set WORK.CNTLINX has 1 observations and 15 variables.
NOTE: The DATA statement used 0.00 CPU seconds and 20207K.
NOTE: The address space has used a maximum of 660K below the line and
21192K above the line.
25 + data=cntlinx; run;
NOTE: Appending WORK.CNTLINX to WORK.CNTLIN.
NOTE: There were 1 observations read from the data set WORK.CNTLINX.
NOTE: 1 observations added.
NOTE: The data set WORK.CNTLIN has 1 observations and 15 variables.
NOTE: The PROCEDURE APPEND used 0.05 CPU seconds and 23815K.
NOTE: The address space has used a maximum of 660K below the line and
24812K above the line.
25 + proc delete data=header ranges labels
cntlinx; run;
NOTE: Deleting WORK.HEADER (memtype=DATA).
NOTE: Deleting WORK.RANGES (memtype=DATA).
NOTE: Deleting WORK.LABELS (memtype=DATA).
NOTE: Deleting WORK.CNTLINX (memtype=DATA).
NOTE: The PROCEDURE DELETE used 0.00 CPU seconds and 23827K.
NOTE: The address space has used a maximum of 660K below the line and
24824K above the line.
25 +
proc format cntlin=CNTLIN fmtlib library=WORK.formats;
NOTE: Format TEMP has been output.
25 +
run;
NOTE: The PROCEDURE FORMAT used 0.02 CPU seconds and 23943K.
NOTE: The address space has used a maximum of 660K below the line and
24944K above the line.
NOTE: There were 1 observations read from the data set WORK.CNTLIN.
25 +
;
NOTE: Deleting WORK.MEMLIST (memtype=DATA).
NOTE: The PROCEDURE DELETE used 0.00 CPU seconds and 23943K.
NOTE: The address space has used a maximum of 660K below the line and
24944K above the line.
|
Here is the first line of the program. It needs to be modified to point to your existing load library that contains the SAS Version 5 format. You must keep the DCB attributes and the ddname of SASLIBX.
filename saslibx "SASCTP.V5.FMTEST" lrecl=32760 blksize=32760;
The following statement illustrates how we call the macro program. This statement is explained in detail in the comments section of the attached program.
%macro convert_fmtlib(v5fmtlib=SASLIBX,cntlin=CNTLIN,fmtlib=WORK,fmtcat=FORMATS);
With this, you can see that the new format is stored in the Work library. After you have successfully run the program, you should modify the location so that it is stored on disk. To do this, add a JCL DD statement that points to your new SAS library, and use your ddname for the argument WORK in the macro call above.
| Type: | Usage Note |
| Priority: |
| Date Modified: | 2011-05-11 14:04:32 |
| Date Created: | 2010-11-03 19:26:59 |




