CC25 ABSTRACT A Macro to Keep Titles and Footnotes in One Place John Morrill, Quintiles, Inc., Kansas City, MO A large project with titles and footnotes in each separate program can be cumbersome to maintain. Consistency can be a problem and last minute changes require altering each program. This paper describes a method of collecting titles and footnotes into a single file and accessing these with a simple macro call. The complete macro is presented and explained with discussion also touching on possible enhancements as well as negatives and usage notes. The ease of use of this macro (which has at most one parameter) makes this paper appropriate for beginners while the convenience of the macro makes it worthy of consideration for all levels of SAS users. INTRODUCTION This paper is organized into five sections. The first section is a discussion of the need for collecting titles and footnotes into a single file. The second presents the format of title.txt, the text file containing all project titles and footnotes. The third shows an example program call and output. The fourth presents the HTF macro. The fifth section is a discussion of negatives, enhancements, and usage notes. 1. FEATURES OF CENTRAL TITLE AND FOOTNOTE PROCESSING Consider this scenario: a project involving scores of programs is due tomorrow and the client wishes to make changes to all titles. A traditional approach of maintaining titles in individual files may require hours of work to alter each file or, worse, having to tell the client that the requested change would delay timelines. You, however, have collected all titles and footnotes into a single file. Each of your programs has a single macro call with a single parameter identifying that program (and even that can be eliminated). The changes can be made quickly and consistently by opening a single file. This reduces the potential need for large-scale re-validation and revision history entries. Further, your suite of programs will be free of projectspecific titles and footnotes, making it easier to borrow code for the next project. Finally, this approach allows specialization which could be performed by someone without SAS expertise. 2. TITLE.TXT, THE REPOSITORY Below are the first several lines of the title.txt file containing titles and footnotes for every program in the project. It is organized into a header section containing titles common to all outputs and then a section of titles and footnotes unique to each output, one section per program. In this example, output test will have nine titles. The first three are found in the h1 through h3 rows, titles that appear on every output across the study. The next six are found on the t1 through t6 rows immediately under the progname=test line. These are unique to this output. The third header and the sixth title are blank, meaning that in the test output, the third and ninth titles will be blank. Two footnotes, found in the F1 and F2 lines, will show up in the test output. The footnote lines in this case begin with capital letters not as a requirement but simply because in many fonts, the lower case T and F are difficult to distinguish. Macro variables can be used to populate entire lines or portions of lines common to multiple outputs. The L, C, and R preceding the equal sign in headers, titles or footnotes indicate the horizontal position (Left, Center, or Right) of the resulting title or footnote. For example, t5r indicates that the text after the equal sign will be padded with blanks on the left such that this text extends to the right edge of the output as specified (or defaulted) by the linesize. See the output in section 3 for illustration. If no L, C, or R appears, the horizontal positioning of the title or footnote is controlled by the center/nocenter option in effect at the time of the %htf macro call. The text file approach was selected as it can be populated with tools (Juneja, 2003) that harvest titles from spreadsheets or mock tables/shells and is platform independent. h1=first header for Acme study h2=second header for Acme study h3= progname=test t1=first title for Acme study t2=second title for Acme study t3l=third title for Acme study (left) t4c=fourth title for Acme study (center) t5r=fifth title for Acme study (right) t6= F1=first footnote for Acme study
F2=second footnote for Acme study progname=test2 t1=acme study test2 first title t2=acme study test2 second title t3= F1=Acme study test2 first footnote F2=Acme study test2 second footnote 3. EXAMPLE CALL AND OUTPUT TEST.SAS %include "setup.sas"; %let prgmname=test; %htf(progname=&prgmname); data any; input p a b c; cards; 1 1 2 3 1 4 5 6 1 7 8 9 2 1 2 3 2 4 5 6 2 7 8 9 ; proc print; by p; pageby p; TEST.LST (multiple spaces removed) first header for Acme study second header for Acme study first title for Acme study second title for Acme study third title for Acme study (left) fourth title for Acme study (center) fifth title for Acme study (right) p=1 Obs a b c 1 1 2 3 2 4 5 6 3 7 8 9 first footnote for Acme study second footnote for Acme study --------------------------------------------------------------------------- first header for Acme study second header for Acme study first title for Acme study second title for Acme study third title for Acme study (left) fourth title for Acme study (center) fifth title for Acme study (right) p=2
Obs a b c 4 1 2 3 5 4 5 6 6 7 8 9 first footnote for Acme study second footnote for Acme study 4. THE HTF MACRO The HTF macro is shown below in its entirety. It is not particularly complex so its internal documentation will serve to suggest its workings. The two filenames at the beginning of the macro could alternatively be defined in a setup file. %macro htf(progname=); filename htf "title.txt"; filename htf_out "title_out_&progname..sas"; %let option_ls=%trim(%sysfunc(getoption(linesize))); data any; length line $800 ltype $1; format tae tae_lcr $char&option_ls..; infile htf missover length=reclen;* obs=15; input line $varying800. reclen; cline=compress(upcase(line),' LCR'); LCRline=compress(upcase(line),' 0123456789HTF'); ** All lines must have an equal sign. **; if indexc(line,'=') GT 0; ** Categorize header, program, title, and footnote lines. **; if substr(left(upcase(line)),1,1)='h' then ltype='h'; else if substr(left(upcase(line)),1,1)='t' then ltype='t'; else if substr(left(upcase(line)),1,1)='f' then ltype='f'; else if substr(left(upcase(line)),1,1)='p' then ltype='p'; ** Determine the number before the equal sign. **; if ltype IN ('H' 'T' 'F') then nbe=input(substr(cline, indexc(cline,'0123456789'), indexc(cline,'=')-indexc(cline,'0123456789')),best5.); ** Determine the horizontal position parameter before the equal sign. **; if ltype IN ('H' 'T' 'F') and substr(lcrline,1,1) IN ('L' 'C' 'R') then hbe=substr(lcrline,1,1); ** Determine the text after the equal sign. **; if ltype IN ('H' 'T' 'F' 'P') AND (indexc(cline,'=') NE length(cline)) then tae=substr(line, (indexc(line,'=')+1), length(line)-indexc(line,'=')); if ltype IN ('P') then tae=compress(tae); l_tae=length(tae); l_line=length(line); o_ls=&option_ls; space_lr=o_ls-l_tae; space_c=int(space_lr/2); if hbe NOT IN ('L' 'C' 'R') then tae_lcr=tae; else do; if hbe='l' then tae_lcr=trim(tae) repeat(' ',max(space_lr-1,0)); if hbe='c' then tae_lcr=repeat(' ',max(space_c-1,0)) trim(left(tae)) repeat(' ',max(space_c-1,0)); if hbe='r' then tae_lcr=repeat(' ',max(space_lr-2,0)) trim(left(tae)); end; *proc contents; *proc print width=min data= any(drop=cline LCRline line) noobs; * where ltype='t'; * ** Count number of headers. **; proc sql noprint;
select count(/*distinct*/ ltype) into :_h from any where ltype='h'; quit; ** Assign appropriate progname to each title and footnote. **; ** Add header count to titles. **; data any(drop=cline LCRline line nbe space: o_ls l_tae l_line); set any; length p $99; retain p; if ltype='p' then p=tae; if ltype IN ('T') then n=nbe+&_h; else n=nbe; data any_q; set any(where=(ltype='h' OR p="&progname")); ** Count number of headers. **; proc sql noprint; select count(ltype) into :_ht from any_q where ltype IN ('H' 'T'); select count(ltype) into :_f from any_q where ltype IN ('F'); quit; data _null_ ; set any_q(where=(ltype NE 'P')); file htf_out ; if ltype IN ('H' 'T') then put @1 "title" n '"' tae_lcr $char&option_ls.. +(-1) '";' ; if ltype IN ('F') then put @1 "footnote" n '"' tae_lcr $char&option_ls.. +(-1) '";' ; run ; quit ; %include "title_out_&progname..sas"; ** Cleaning operation - first intermediate file then data sets. **; data _null_; fname="interm"; rc=filename(fname,"title_out_&progname..sas"); if rc = 0 and fexist(fname) then rc=fdelete(fname); rc=filename(fname); proc datasets nolist; delete any_q any; %mend htf; 5. NEGATIVES, ENHANCEMENTS AND USAGE NOTES One negative to the htf macro / title.txt approach is that multiple programmers may need to access the title.txt file. This can be overcome with proper communication or by assigning a single person to be responsible for updates or perhaps some kind of version control. This negative may be outweighed by the gain in consistency a single file achieves. Another criticism of the title.txt approach is that a SAS program collecting all headers, titles, and footnotes could be easily designed, achieving the same results with less complexity. While this may be true, title.txt can be maintained by someone without programming experience which may be an advantage. A number of enhancements could be made to the htf macro. It could perform a consistency check of the title.txt file to ensure that everything is in its place. A check could also verify that no conflicting titles or footnotes exist in the SAS program calling the htf macro.
From the user s perspective, there is nothing keeping macro variables from being used with title.txt and a page numbering macro could be used to allow any number of page number styles (e.g., page x of y). A position-holding token could be placed in title.txt and a post-processing macro could be used to detect the page number with which to replace this token. And a dummy progname could be used to record a revision history or store a library of special characters for convenient use. Finally, it is wise to issue this macro immediately before the titles are needed to avoid conflict with titles or footnotes that may be left over from testing stages. REFERENCES Raj Juneja in 2003 (unpublished) developed a SAS macro which harvests into a SAS data set a project s entire set of titles and footnotes from MS Word document mock tables. Titles and footnotes can also be read from an MS Excel worksheet. Title.txt can easily be populated from a SAS data set. Having this flexibility reduces start-up time and improves options for checking consistency. Contact Mr. Juneja at raj_juneja@hotmail.com. ACKNOWLEDGMENTS The author wishes to thank Dr. Philip Doren, Dr. Indra Fernando, John Gorden, Doug Moore, Tony Salehi, and Kelley Weston for valuable review and suggestions. SAS is a registered trademark or trademark of SAS Institute Inc. in the USA and other countries. indicates USA registration. Other brand and product names are registered trademarks or trademarks of their respective companies. CONTACT INFORMATION Your comments and questions are valued and encouraged. Contact the author by phone at 816-767-6000, by mail at Quintiles, Inc., P.O. Box 9708, Kansas City, MO 64134-0708, or by E-mail at John.Morrill@Quintiles.com. BIO INFORMATION John is an Analyst in Statistical Programming at Quintiles, Inc. in Kansas City. He first used SAS in 1985 and has used it fulltime in the pharmaceutical industry since 1998. KEYWORDS Title, Footnote, Header, Macro