BookmarkSubscribeRSS Feed

Recreating the code that *could* have been used to create a format

Started ‎05-02-2018 by
Modified ‎05-25-2018 by
Views 2,873

Many years ago I worked on an old IBM VM/CMS box which was at end-of-life, but not-quite-yet. The platform manager had a cartoon of two old guys digging in a cemetery with the caption, "I know we buried that old mainframe around here somewhere..."


One of the old projects I was working on made extensive use of formats, but the source code of those formats was long lost. Using cntlout in proc format allowed us to edit the formats and republish them, but it frustrated the hell out of me that it was such a laborious process.


So I wrote one of the macros I'm proudest of: %genfmt. OK, it's not such a great name, but it does just that - it generates or recreates format code.


Over the years I've upgraded it a bit from its humble value beginnings, especially to include invalue (character and numeric) and picture types. Using invalues is interesting - to get the select statement to work, you have to prefix the format name with @. Not many people know that.



%genfmt(library=library, format=format name, ovrwrite=n*sasgen=debug=n**)


*Because the code writes out a file called format name.fmt, this stops it proceeding if this file already exists. If you don't care, or it doesn't exist, you'll get:

INFO: The format generation code is stored in file "$clevel.fmt". 

in your log.


The output code's filename can be replaced by sasgen.


**Shows the code generated by the macro in the log


As a side effect, I found that it does a pretty good job of compressing format code as well. For example, here's an old format I was working on just this morning:

	value $clevel	 	
		'<2B' = '<2'
		'2B' = '2'
		'2P' = '2'
		'2A' = '2'
		'3B' = '3'
		'3P' = '3'
		'3A' = '3'
		'4B' = '4'
		'4P' = '4'
		'4A' = '4'
		'5B' = '5'
		'5P' = '5'
		'5A' = '5'
		'6B' = '6'
		'6P' = '6'
		'6A' = '6'
		'>6A'= '>6A'



I applied genfmt to it and this was spat out:


value $clevel
"2A", "2B", "2P" = "2"
"3A", "3B", "3P" = "3"
"4A", "4B", "4P" = "4"
"5A", "5B", "5P" = "5"
"6A", "6B", "6P" = "6"
"<2B" = "<2"
">6A" = ">6A";

There's nothing particularly clever in the code, but I have documented it pretty well, I think, so you can see what I've done and how I've done it. Note that it copes with quotes within labels, inclusive/exclusive ranges, other values, imbeded formats and, I think, pretty much everything else.



This is, as ever, open source - use it in health, and let me know if you've liked it and especially if you've found any bugs. Payment can be made in beer.


There  must be a lot of details buried by

Using cntlout in proc format allowed us to edit the formats and republish them, but it frustrated the hell out of me that it was such a laborious process.


I'll be playing with this a bit to see if it handles multilabel formats in a nice form.

Hmm (runs off to the hills in fear of multilabel formats)


To be honest, they might work, but again they might not!


Another good reason to avoid using compiled catalogs.  We are (hopefully) moving towards a more open source future, so keeping formats and programs and macros in plain text files, easily portable, easily readable and usable, and not affected by things like OS bit changes.  The benefits of catalogs, in my opinion is none, for years being used as a means to hide code from users which is just bad.

I don't disagree. I love formats, and have since 1979. But the majority of the time I am working in organisations where I have little or no control over the environment and have to cut my coat to suit the cloth.


I've started to move away from formats in a production environment, because as often as not there's not enough source management control over them and there are often multiple versions floating around. That's why we have single repositories of the truth, in databases and warehouses. But they still have their uses.


However, as I pointed out above, if you are going to use formats, using this macro can allow you to reformat the code to make it a bit more manageable.

@LaurieF - I see from the comment history that you began work on this in 1997.  Thanks for getting around to sharing it now! Better late than never 🙂

Well, I didn't want to rush things.

@ballardw As of today, it now supports multilabel and notsorted options.


Amusingly multilabel and notsorted are represented in the hlo variable as M (fine)and S (what?!) respectively. Yes, notsorted maps on to S!


Well, it at least it will support them once I've worked out how to replace the attachment. @ChrisHemedinger, can you give me a hand?

@LaurieF: Thanks for posting and I look forward to downloading the code after @ChrisHemedinger helps you upload the revised code.


Art, CEO,


@LaurieF Happy to help - you should be able to Edit and add an attachment.  Do you see the Attachment field when you Edit?



If you get stuck, you can e-mail the file to me ( and I'll handle it.

Hi all - I've updated the attachment for Laurie.

Version history
Last update:
‎05-25-2018 09:01 AM
Updated by:



Registration is open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.

If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website. 

Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags