The day before yesterday, I posted a paper on how to combine PDF files via Excel VBA. Then I got a comment from reader who’d like to combine Portrait rtf files and Landscape rtf files into one single rtf file. And this post will focus on how to fix the issue.

Why we can combine RTF files via SAS

If you right click on a rtf file and choose to open it in Notepad or Notepad++ (which is better), you will find that RTF file are written in a language called RTF code and are organized in good structure. This post will give you a brief introduction if you are not familiar with RTF code. And here is the code which can read rtf files into SAS dataset.

Click here to hide/show code


data rtf;
length rtfcode $32767;
infile “&path/sample.rtf” lrecl=32767 end=eof;
input;
rtfcode = _infile_;
run;

A rtf file consists of unformatted text, control words or symbols. Control words or symbols can put unformatted text together and formatted them into something which RTF reader like Microsoft Word can understand and thus turn it into something which are human readable. Based on this principle, we can add or remove some control words/symbols to change how Microsoft display a rtf file. Or we can also add or remove some new unformatted text and change the content of a rtf file. To change control words or unformatted text, we only need to use our common functions like SUBSTR, INDEX, CONCATENATE, DELETE, etc.

How to combine multiple RTF files into one file

We can think in this way, each rtf file is like a sandwich and consists of three parts, opening section, content section and closing section. By keeping the opening section of first rtf file, removing both opening and closing sections of rtf files between first and last rtf file, keeping closing section of last file, and then putting them together in sequence, you will get a new combined file.

A simple macro to combine rtf files into one single rtf file

To combine multiple files into a rtf file, we need to know which files are to be bundled. The easiest way is to use SAS code to retrieve names of all files and then concatenate the macro variable inpath with filenames to get full path of each file. Then we can read them one by one into SAS dataset and do some necessary manipulation before setting them together. Here is code which can combine all files within a folder. Here I need your attention. control words such as \paperwN or \paperhN which can determine if the page displayed in landscape or portrait must be removed if you want to bundle any type of rtf files no matter if they are in landscape or portrait mode.

Click here to hide/show code


%macro m_combrtf(inpath= ,outpath= ,outfile= );

*Get rtf file names from a folder;
data rtffiles(keep=fileloc fnm);
length fref $8 fnm $80 fileloc $400;

rc = filename(fref, “&inpath”);
if rc = 0 then did = dopen(fref);

dnum = dnum(did);

do i = 1 to dnum;
fnm = dread(did, i);
fid = mopen(did, fnm);
if fid > 0 and index(fnm,’rtf’) then do;
fileloc=”&inpath/”||left(trim(fnm));
fnm = strip(tranwrd(fnm,”.rtf”,””));
output;
end;
end;
rc = dclose(did);
run;

*Sort rtf files by tfl number;
data rtffiles(keep= fileloc ord tflno);
length tflno $200 ;
set rtffiles;

if index(fnm,”_t_”) then ord = 1;
else if index(fnm,”_f_”) then ord = 2;
else if index(fnm,”_l_”) then ord = 3;

tflno = strip(tranwrd(fnm,”.rtf”,””));
run;

proc sort data = rtffiles; by ord tflno; run;

*Create macro variable which contains all rtf files;
proc sql noprint;
select quote(strip(fileloc)) into :rtffiles separated by ‘, ‘
from rtffiles;
quit;
filename rtffiles (&rtffiles); * create filename rtffiles ###;

*Start;
proc sql noprint;
select fileloc into :fileloc from rtffiles(obs = 1);
quit;
data start;
length rtfcode $32767;
infile “&fileloc” lrecl = 32767 end = eof;
input ;
rtfcode = _infile_;

retain kpfl strfl;

if substr(rtfcode,1,6)=’\sectd’ then kpfl=1;
if index(rtfcode, “\paperw”) and index(rtfcode,”\paperh”) then delete;
if kpfl = . then output start;
run;

*data rtf;
data rtf(keep = rtfcode);
length rtfcode $32767 tflnam $1000;
set rtffiles end=last;
sof+1;
retain kpfl ;

do until (eof);
infile rtffiles lrecl=32767 end=eof filevar=fileloc;
input;
rtfcode=_infile_;

*Remove RTF header section and replce \sectd with \pard\sect\sectd;
if sof then kpfl=.;
if substr(rtfcode,1,6)=’\sectd’ then do;
num+1;
kpfl=1;
if num = 1 then rtfcode=compress(tranwrd(rtfcode,’\pgnrestart\pgnstarts1′,”));
else rtfcode=’\pard\sect’||compress(tranwrd(rtfcode,’\pgnrestart\pgnstarts1′,”));
end;

*Remove RTF closing } except for last file;
if eof and not last then delete;

*output concatenated rtf;
if kpfl=1 then output rtf;

sof=0;
end;
run;

data _null_;
file “&outpath/&outfile..rtf” lrecl=32767 nopad;
set start rtf; *concatenate rtf header,document info, all rtf files;
put rtfcode;
run;

%mend m_combrtf;

%let outpath=&tlfpath./New Folder;
%let inpath=&tlfpath./New Folder;
%let outfile = sample;

%m_combrtf(inpath = &inpath,
outpath = &outpath,
outfile = &outfile);

Note:

Here is the opening section for whole bundled file, you can see that no page information exists since I have removed “\paperw15840\paperh12240\margl1440\margr1440\margt1440\margb540” which should have been the last line of this opening section. And you can update here based on your own rtf code.

I know that different company put titles and footnotes in different places. Some may place them in header & footer section and some may place them in the body of rtf document. Above macro will works no matter how you place the titles and footnotes.