Cut and paste the following cell's content into NOTEPAD to strip off html tags then upload to your mainframe.

Or download via this link: SASPRINT


*PROGRAM-NAME=SASPRINT;
*PROGRAM-TITLE=PRETTY PRINT FOR SAS PROGRAMS;
*PROGRAM-AUTHOR=JESSE LANE;

/********************************************************************/
/* */
/* SASPRINT: */
/* - UTILITY TO PROVIDE A FORMATTED LISTING OF A SAS PROGRAM */
/* - COMPLETE WITH A COPYRIGHT NOTICE, MODULE NAME, TITLE, */
/* - AUTHOR, AND WELL-PLACED PAGE EJECTS TO IMPROVE READABILITY. */
/* */
/* 1) IN YOUR SAS PROGRAM, PUT A CARD CONTAINING ONLY '*EJECT;' */
/* ANYWHERE YOU WISH THE LISTING TO EJECT TO A NEW PAGE. */
/* ADD THESE PARAMETERS AT THE START OF YOUR SAS PROGRAM: */
/* *PROGRAM-NAME=<MODULE NAME>; */
/* *PROGRAM-TITLE=<ANY TITLE YOU WANT>; */
/* *PROGRAM-AUTHOR=<YOUR NAME>; */
/* 3) USE A %LET LIBRARY= STATEMENT TO SET THE LIBRARY */
/* WHERE YOUR SAS PROGRAMS/JOBS ARE STORED. */
/* 4) USE A %LET PROGRAM= STATEMENT TO NAME THE MODULE */
/* WITHIN THAT LIBRARY WHICH YOU WISH TO PRINT. */

/* 5) FIR */
/* */
/* NOTE: YOU CAN PRINT AS MANY DIFFERENT MODULES FROM AS MANY */
/* DIFFERENT LIBRARIES AS YOU LIKE BY ADDING ADDITIONAL %LET */
/* MODULE= AND %LET LIBRARY= CARDS (PLUS THE CALL TO THE MACRO) */
/* */
/* THIS UTILITY WAS CREATED BY JESSE LANE OF LOGICAL VISIONS dba */
/* */
/********************************************************************/

%MACRO PARM_SEARCH;
SEARCH_STRING = "&SEARCH_STRING";
POS = INDEX(LINE,TRIM(SEARCH_STRING));
IF POS GT 0 AND POS LT 15 THEN
DO;
FIRST_POS = POS + LENGTH(TRIM(SEARCH_STRING));
LAST_POS = LENGTH(TRIM(LINE))-1; *NO SEMI-COLON;
PARM_LENGTH = LAST_POS - FIRST_POS + 1;
*PUT SEARCH_STRING=
POS= FIRST_POS= LAST_POS= PARM_LENGTH=;
IF PARM_LENGTH > 0 THEN
RETURN_STRING = SUBSTR(LINE,FIRST_POS,PARM_LENGTH);
ELSE
RETURN_STRING = ' ';
IF RETURN_STRING = ' ' THEN RETURN_STRING = '<PARM MISSING>';
IF "&RETURN_VAR"="P_NAME" THEN
RETURN_STRING = COMPRESS(SUBSTR(RETURN_STRING,1,8),' ;');
ELSE
RETURN_STRING = TRIM(COMPRESS(RETURN_STRING,'*;'));
CALL SYMPUT("&RETURN_MVAR",TRIM(RETURN_STRING));
&RETURN_VAR = RETURN_STRING;
END;
%MEND PARM_SEARCH;

*EJECT;

%MACRO PGMLIST(LIBRARY=UNKNOWN,
MODULE=UNKNOWN,
COPYRIGHT_OWNER=UNKNOWN,
COPYRIGHT_YEAR=UNKNOWN,
CENTER=CENTER
);

OPTION &CENTER;

FILENAME PROGRAM "&LIBRARY(&MODULE)";

DATA PROGRAM;
INFILE PROGRAM;
RETAIN LINENO 0 SECTION 1;
LENGTH SEARCH_STRING RETURN_STRING $ 80;

INPUT @1 LINE $CHAR80.;
LINENO = LINENO + 1;

IF INDEX(LINE,'*EJECT') GT 0 AND
INDEX(LINE,'*EJECT') LT 15 THEN
DO;
SECTION = SECTION + 1;
DELETE;
END;


%LET SEARCH_STRING=*PROGRAM-NAME=;
%LET RETURN_VAR=P_NAME;
%LET RETURN_MVAR=P_NAME;
%PARM_SEARCH;
DROP P_NAME;

%LET SEARCH_STRING=*PROGRAM-TITLE=;
%LET RETURN_VAR=P_TITLE;
%LET RETURN_MVAR=P_TITLE;
%PARM_SEARCH;
DROP P_TITLE;

%LET SEARCH_STRING=*PROGRAM-AUTHOR=;
%LET RETURN_VAR=P_AUTHOR;
%LET RETURN_MVAR=P_AUTHOR;
%PARM_SEARCH;
DROP P_AUTHOR;

RUN;

OPTION PAGENO=1;
PROC PRINT DATA=PROGRAM UNIFORM;
*TITLE "MODULE: &P_NAME (&P_TITLE), "
"AUTHOR: &P_AUTHOR, "
"COPYRIGHT &COPYRIGHT_YEAR &COPYRIGHT_OWNER";
TITLE "MODULE: &LIBRARY(&MODULE) "
"COPYRIGHT &COPYRIGHT_YEAR &COPYRIGHT_OWNER";
BY SECTION;
PAGEBY SECTION;
ID LINENO;
VAR LINE;
RUN;

%MEND PGMLIST;