/* * Make FDA-compliant pdfmark'ed distallable PostScript. * * (c) 2003 SAS Institute Inc. * * * That is, with this macro you can readily produce PostScript * output which you can then distill into PDF that will be FDA * compliant. * * In order to "distill" PostScript into PDF, you must have a third- * party product, such as Adobe Acrobat Distiller (sold as part of * the Adobe Acrobat product for Windows; or ps2pdf, which is part * of the Ghostscript programs for Unix systems (including Linux). * * Usage * * make_compliant(tempfile, filename); * tempfile Is the name of the temporary file supplied to * ODS PRINTER or ODS PS. * filename Is the name of the final postscript file - the * one that you will then distill to produce the * PDF output. * * Usage: * * ods ps pdfmark file=".tmp" . . .; * : * [sas code] * : * ods ps close; * * %make_compliant(".tmp", ".ps"); * * PC: Easiest is to set up a "watched folder" with distiller and simply * specify as the folder; eg, C:\watched\folder\myfile.ps * * Unix: x ps2pdf myfile.ps; */ %let had_fitr = no; %let had_gotor = no; ods listing close; %macro make_compliant(tempfile, permfile); data _null_; infile &tempfile lrecl=25000 pad; file &permfile lrecl=25000; length line $25000; length x1 $20 y1 $20 x2 $20 y2 $20; length had_fitr $10 had_gotor $10; input line $char.; /* * Convert << /S URI into a Launch action UNLESS it specifies * a # named destination, because Launch does not appear to * support them, so what's the point of generating invalid * output? * We should use URI for http: goobers, but my code (darn it) * forces http: on all names, so do something more complex. */ place = index(line, "<< /S /URI"); place2 = index(line, "#"); if place = 1 && place2 = 0 then do; place2 = index(line, ">>"); place + 16; file = substr(line, place, place2 - place); if index(file, "://") > 0 then line = "/Launch /URI " || file; else do; if index(file, "http:") = 2 then do; file = "(" || substr(file, 7, length(file)-6); end; line = "/Launch /File " || file; end; end; /* * It seems that /Dest cannot be used with Launch, so we want * conform GoToR into Launch normally but NOT if a /Dest is * used. * Luckily IF present, the file goes: /GoToR\n/Dest . . . * Still, this is yucky. But you gotta do what you gotta do. */ had_gotor = symget('had_gotor'); if had_gotor = 'yes' then do; if index(line, '/Dest') = 1 then line = '/GoToR ' || line; else line = '/Launch ' || line; call symput('had_gotor', 'no'); end; else do; place = index(line, "/GoToR"); if place = 1 then do; line = ""; call symput('had_gotor', 'yes'); end; end; /* Change view to XYZ */ had_fitr = symget('had_fitr'); if had_fitr = 'yes' then do; x1 = scan(line, 1, ' '); y1 = scan(line, 2, ' '); x2 = scan(line, 3, ' '); y2 = scan(line, 4, ' '); line = trim(x1) || ' ' || trim(y2) || ' 0'; call symput('had_fitr', 'no'); end; else do; place = index(line, "/FitR"); if place = 1 then do; line = "/XYZ"; call symput('had_fitr', 'yes'); end; end; put line; run; %mend;