/*

/ Program   : fmts2fda.sas
/ Version   : 1.0
/ Author    : Roland Rashleigh-Berry
/ Date      : 31-Jul-2007
/ Purpose   : To create sas code to generate formats as found in your data
/ SubMacros : %quotelst
/ Notes     : The FDA sometimes requests the user-defined formats you are using
/             in your datasets. You can either send them the full format catalog
/             members or use this utility so that the formats can be generated.
/             This will only give you the codes and their formatted values as it
/             occurs in your data. It will NOT give all codes defined to the
/             formats. If you want all possible codes mapped then send them the
/             format catalogs and do not use this utility.
/
/             Note that this utility is weak on numeric formats. These can be
/             very long lists of values. You should just use this to identify
/             what numeric formats are being used and replace the generated code
/             with the original code for the numeric format.
/
/ Usage     : %fmts2fda(mylib1 mylib2)
/ 
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ libname           (pos) Libref of the library where your datasets are stored.
/                   More than one can be specified (separated by spaces).
/ file=fdaformats.sas    Name of the flat file that will hold the formats code
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb  29Mar07         Put out "macro called" message plus header tidy
/ rrb  31Jul07         Header tidy
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/

%put MACRO CALLED: fmts2fda v1.0;

%macro fmts2fda(libname,file=fdaformats.sas);

%if not %length(&libname) %then %let libname=%sysfunc(getoption(user));
%if not %length(&libname) %then %let libname=work;


*- find all datasets and variables in the library that have -;
*- user-defined formats and output to a dataset -;
proc sql noprint;
  create table _fmts as
  select libname, memname, name, type, format
  from dictionary.columns
  where libname in (%quotelst(%upcase(&libname)))
  and memtype='DATA'
  and compress(format,'F$0123456789.') 
    not in (' ' 'DATE' 'TIME' 'DATETIME' 'CHAR' 'BEST' 'Z');
quit;


%*- warn if no user formats and exit -;
%if not %nobs(_fmts) %then %do;
  %put WARNING: (fmts2fda) No user-defined formats are used in library=&libname;
  data _null_;
    file "&file";
    put "No user-defined formats are used in library=&libname";
  run;
  %goto skip;
%end;


%*- delete base dataset if it already exists -;
%if %sysfunc(exist(_fmtbase)) %then %do;
  proc datasets nolist;
    delete _fmtbase;
  run;
  quit;
%end;


*- for each dataset, sort nodupkey, add the format name and type, -;
*- assign the variable contents to variable "start" and append on -;
*- to the base dataset. -;
data _null_;
  set _fmts;
  call execute('proc sort nodupkey data='||trim(libname)||'.'||trim(memname)||'(keep='||
    trim(name)||') out=_fmtbit;by '||trim(name)||';run;');
  call execute('data _fmtbit;length type $ 4 format start $ 20;retain format "'||
    trim(format)||'" type "'||type||'";set _fmtbit;');
  if type='char' then call execute('start='||trim(name)||';drop '||trim(name)||';run;');
  else call execute('start=trim(left(put('||trim(name)||',best16.)));drop '||trim(name)||';run;');
  call execute('proc append base=_fmtbase data=_fmtbit;run;');
run;


*- get rid of duplicates from the base dataset -;
proc sort nodupkey data=_fmtbase;
  by format type start;
run;


*- write the "proc format" code out to the flat file -;
data _null_;
  length fmt $ 20 label $ 40;
  file "&file" noprint notitles;
  set _fmtbase end=last;
  by format;
  if _n_=1 then put 'proc format;';
  fmt=compress(format,'.');
  if first.format then put @3 'value ' fmt;
  if type='char' then do;
    label=putc(start,format);
    put @5 '"' start +(-1) '"="' label +(-1) '"';
  end;
  else do;
    label=putn(input(start,best16.),format);
    put @5 start +(-1) '="' label +(-1) '"';
  end;
  if last.format then put @3 ';';
  if last then put 'run;';
run;


*- tidy up -;
proc datasets nolist;
  delete _fmts _fmtbase _fmtbit;
run;
quit;



%skip:
%mend;