Data to Format

Purpose: Create a format using values from a data set

/******************* URBAN INSTITUTE MACRO LIBRARY *********************
 
 Macro: Data_to_format
 Description: Create a format using values from a data set
 
 Use: Open code
 
 Author: Peter Tatian
 
***********************************************************************/

%macro Data_to_format( 
  FmtLib=work,    /* Optional: Format library (def. WORK) */
  FmtName=,       /* Format name (start w/$ for char format) */
  DefaultLen=.,   /* Optional: Default format length */  
  MaxLen=.,       /* Optional: Maximum format length */
  MinLen=.,       /* Optional: Minimum format length */
  InDS=,          /* Input data set */
  Data=,          /* Input data set (alias) */
  Value=,         /* Value to be formatted (num or char expression) */
  Label=,         /* Label to use for formatted value (char expression) */
  NotSorted=N,    /* Specify NOTSORTED option for format (Y/N) */
  OtherLabel=,    /* Optional: Label to use for values not in format (char string) */
  Desc=,          /* Optional: Description of format for catalog (char string) */
  Contents=N,     /* Optional: List contents of format catalog (Y/N) */
  Print=Y         /* Optional: Print resulting format (Y/N) */
  );

  /*************************** USAGE NOTES *****************************
   
   SAMPLE CALL: 
     %Data_to_format(
       FmtLib=General,
       FmtName=$anc12a,
       Data=General.ANC2012,
       Value=ANC2012,
       Label=ANC2012_name,
       OtherLabel="Not a valid ANC"
       )
       create format $anc12a in General.Formats catalog that converts
       values given by var ANC2012 to labels in var ANC2012_name from
       data set General.ANC2012.
       Values not found in ANC2012 will be labeled "Not a valid ANC"
  
  *********************************************************************/

  /*************************** UPDATE NOTES ****************************
    11/23/04  Added Data= parameter (alias for input data set name),
              check for required parameters.
    03/30/06  Added Contents= and Desc= parameters.
    10/22/06  Added NotSorted= parameter.
  *********************************************************************/

  %***** ***** ***** MACRO SET UP ***** ***** *****;
   
  %local type fmtcat;
  
  %Note_mput( macro=Data_to_format, msg=Starting macro. )

    
  %***** ***** ***** ERROR CHECKS ***** ***** *****;

  %if %length( &InDS ) = 0 %then %let InDS = &Data;
  
  %if %length( &InDS ) = 0 %then %do;
    %Err_mput( macro=Data_to_format, 
                 msg=Must provide an input data set in Data= or InDS= parameter. )
    %goto err_exit;
  %end;

  %if %length( &FmtName ) = 0 %then %do;
    %Err_mput( macro=Data_to_format, 
                 msg=Must provide a format name in FmtName= parameter. )
    %goto err_exit;
  %end;

  %if %length( &Value ) = 0 %then %do;
    %Err_mput( macro=Data_to_format, 
                 msg=Must provide a num. or char. expression in Value= parameter. )
    %goto err_exit;
  %end;

  %if %length( &Label ) = 0 %then %do;
    %Err_mput( macro=Data_to_format, 
                 msg=Must provide a char. expression in Label= parameter. )
    %goto err_exit;
  %end;


  %***** ***** ***** MACRO BODY ***** ***** *****;
  
  %** TYPE = Type of format (Character/Numeric) **;

  %if %substr( &fmtname, 1, 1 ) = $ %then 
    %let type = C;
  %else 
    %let type = N;
  
  %** FMTCAT = Full name of format catalog **;
  
  %if %sysfunc( indexc( "&fmtlib", '.' ) ) > 0 %then
    %let fmtcat = &fmtlib;
  %else
    %let fmtcat = &fmtlib..formats;
    
  data _cntlin (compress=no);
  
    length hlo $ 8;

    retain fmtname "&fmtname" type "&type" /*hlo "  " */
      default &defaultlen max &maxlen min &minlen;
    
    %if %mparam_is_yes( &NotSorted ) %then %do;
      retain hlo "s";
    %end;
    %else %do;
      retain hlo " ";
    %end;
    
    %if &maxlen > 0 %then %do;
      length label $ &maxlen;
    %end;
    
    set &InDS end=last;
    
    label = &label;
    start = &value;
    
    output;
    
    %if %length( &otherlabel ) > 0 %then %do; 
    
      if last then do;
        hlo = trim( hlo ) || 'o';
        label = &otherlabel;
        output;
      end;
      
    %end;

    keep fmtname type hlo label start default max min;

  run;
  
  proc format library=&fmtlib cntlin=_cntlin;

  run;
  
  proc datasets library=work memtype=(data) nolist;
    delete _cntlin;
  quit;
  
  %** Add format description to catalog **;
  
  %if &desc ~= %then %do;
  
    proc catalog catalog=&fmtcat;
    %if &type = C %then %do;
      modify %substr( &fmtname, 2 ) (desc=&desc) /entrytype=formatc;
    %end;
    %else %do;
      modify &fmtname (desc=&desc) /entrytype=format;
    %end;
    quit;
  
  %end;
  
  %** Print entire format to output **;
  
  %if %mparam_is_yes( &print ) %then %do; 
  
    proc format library=&fmtlib fmtlib;
      select &fmtname;

    run;
    
  %end;
  
  %** List contents of format catalog **;
  
  %if %mparam_is_yes( &contents ) %then %do;

    proc catalog catalog=&fmtcat;
      contents;
    quit;
    
  %end;  
  
  %goto exit;
  
  %err_exit:
  %Err_mput( macro=Data_to_format, msg=Format &FmtName was not created. ) 
  
  %exit:
  %Note_mput( macro=Data_to_format, msg=Exiting macro. )

  %***** ***** ***** CLEAN UP ***** ***** *****;


%mend Data_to_format;


/************************ UNCOMMENT TO TEST ***************************
filename uiautos "K:\Metro\PTatian\UISUG\Uiautos";
options sasautos=(uiautos sasautos);
options mprint nosymbolgen nomlogic;
data A;
  input v $ 1 v_lbl $ 3-9;
  
datalines;
A Label A
B Label B
C Label C
;
run;
proc print data=A;
%Data_to_format(
  FmtLib=work,
  FmtName=$test,
  Desc="Test format",
  Data=A,
  Value=v,
  Label=v_lbl,
  OtherLabel="Not a valid value",
  DefaultLen=.,
  MaxLen=.,
  MinLen=.,
  Print=Y,
  Contents=Y
  )
proc datasets library=work;
quit;
/**********************************************************************/