/*

/ Program   : mkformat.sas
/ Version   : 1.5
/ Author    : Roland Rashleigh-Berry
/ Date      : 02-Jan-2012
/ Purpose   : To create a format out of a "coded" and "decoded" variable in a 
/             specified dataset.
/ SubMacros : %hasvars %varlen
/ Notes     : Use this to generate a format from a coded and decoded variable so
/             that you can report it in coded order but have it displayed in its
/             decoded form by applying the generated format.
/ Usage     : %mkformat(dsname(where=(x>1)),varcd,vardcd,fmtname,fmtcat);
/ 
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ ds                (pos) Input dataset
/ code              (pos) Coded variable
/ decode            (pos) Decoded variable
/ fmtname           (pos) Format name
/ lib               (pos) Catalog library (defaults to work)
/ indent=0          Number of spaces to indent the label
/ underscore=no     Whether to use underscore characters before and after the
/                   label (will override indent= if set to yes)
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb  19Mar07         Macro called message added plus header tidy
/ rrb  30Jul07         Header tidy
/ rrb  19Jan11         Allow modifiers in input dataset specification (v1.2)
/ rrb  30Nov11         indent= parameter added (v1.3)
/ rrb  21Dec11         underscore= processing added (v1.4)
/ rrb  02Jan12         Notes disabled (v1.5)
/===============================================================================
/ 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: mkformat v1.5;

%macro mkformat(ds,code,decode,fmtname,lib,indent=,underscore=no);

  %local errflag err len savopts;
  %let err=ERR%str(OR);
  %let errflag=0;

  %let savopts=%sysfunc(getoption(notes));
  options nonotes;

  %if not %sysfunc(exist(%scan(&ds,1,%str(%()))) %then %do;
    %put &err: (mkformat) Dataset &ds does not exist;
    %let errflag=1;
  %end;

  %if not %length(&fmtname) %then %do;
    %put &err: (mkformat) You must supply a format name;
    %let errflag=1;
  %end;

  %if &errflag %then %goto exit;


  %if not %length(&indent) %then %let indent=0;

  %if not %length(&underscore) %then %let underscore=no;
  %let underscore=%upcase(%substr(&underscore,1,1));

  data _mkfmt;
    set &ds;
  run;

  %if not %hasvars(_mkfmt,&code &decode) %then %do;
    %put &err: (mkformat) Dataset &ds does not contain variable(s) &_nomatch_;
    %let errflag=1;
  %end;

  %if &errflag %then %goto exit;


  proc sort nodupkey data=_mkfmt(keep=&code &decode)
                      out=_mkfmt(rename=(&code=start &decode=label));
    by &code &decode;
  run;

  %let len=%varlen(_mkfmt,label,x);
  %if &underscore EQ Y or &indent GT 0 
   %then %let len=%eval(&len+%sysfunc(max(2,&indent)));

  data _mkfmt;
    length label $ &len;
    retain fmtname "&fmtname";
    set _mkfmt;
    %if &underscore EQ Y %then %do;
      label="_"||trim(label)||"_";
    %end;
    %else %if &indent GT 0 %then %do;
      label=repeat(" ",%eval(&indent-1))||label;
    %end;
  run;

  proc format cntlin=_mkfmt
    %if %length(&lib) %then %do;
      library=&lib
    %end;
    ;
  run;

  proc datasets nolist;
    delete _mkfmt;
  run;
  quit;

  %goto skip;
  %exit: %put &err: (mkformat) Leaving macro due to problem(s) listed;
  %skip:

  options &savopts;

%mend mkformat;