ListMacroDefinitions.sas

/****************************************************************************/
/*  Program Name  : ListMacroDefinitions                                    */
/*  Purpose       : List all macro names as defined in the current program  */
/*                  in the log.                                             */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Author        : Matt Trzcinski                                          */
/*  Last Update   : 2017/04/03                                              */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Note          : Current file must be saved before executing macro. The  */
/*                  program reads in that saved file and parses it for      */
/*                  macro definitions.                                      */
/*                                                                          */
/*                  Macro name is considered to be the set of characters    */
/*                  between the string '%macro ' and the left parenthesis.  */
/*                  This allows for indentation of macro names within the   */
/*                  list by inserting spaces at the beginning of the macro  */
/*                  name.  For example, %macro   ThirdLevelMacro();         */
/*                  Support is included for only 10 macro levels.           */
/*                                                                          */
/*                  It is advised to place this macro inside an AUTOCALL    */
/*                  library so that it may be bound to a shortcut via the   */
/*                  KEYS menu.  AUTOCALL libraries can be found by issuing  */
/*                          %put %sysfunc(pathname(sasautos));              */
/*                  Once placed in an AUTOCALL library, issue:              */
/*                                    dm 'KEYS';                            */
/*                  For a hotkey, assign the following code:                */
/*                        submit '%ListMacroDefinitions();'                 */
/*                  Press Ctrl + s to save the keybinding.                  */
/*                                                                          */
/*  Developer     : Create error handling for case when file is not saved.  */
/*                                                                          */
/*                  It appears impossible to delete a macro from within     */
/*                  that same macro.  As such, ListMacroDefinitions is      */
/*                  not deleted after it is compiled. It may be possible to */
/*                  delete by implementing a shorter macro name and         */
/*                  explicitly calling PROC CATALOG from KEYS.  However,    */
/*                  this approach presents problems when trying to mask     */
/*                  log notes.  KEYS commands are restricted in character   */
/*                  length.                                                 */
/*                                                                          */
/****************************************************************************/
%macro ListMacroDefinitions();

  option nonotes;

  dm 'clear log;';

  /*Assign full path of current program to temporary macro

    variable.*/
  proc sql noprint;
    select distinct xpath
    into : _path trimmed
    from dictionary.extfiles
    where xpath contains "%sysget(SAS_EXECFILENAME)"
    ;
  quit;

  /*Read program in line-by-line and parse for

    macro definitions.  To call this step using

    KEYS requires the file path to be hardcoded.

    SAS cannot dynamically resolve the path. When

    the program is compiled, the path is resolved

    before being saved.*/
  data _null_ / pgm=work.list_macros;
    infile "&_path" dlmstr = '``?`?' lrecl = 32767;
    length
      line      $ 32767
      macroName $ 42 /*ValidV7 macro name is 32 + 10 possible indentation levels*/
    ;
    input line;

    /*Accomodate leading spaces in macro names. Note that

      the position of the cursor after the space in

      '%macro ' is 8*/
    if line =: '%macro' then do;
      lengthFromCol1ToLeftParenthesis = index(line,'(');
      lengthMacroName                 = lengthFromCol1ToLeftParenthesis - 8;
      macroName                       = substr(line, 8, lengthMacroName);
      lengthStrippedMacroName         = length(strip(macroName));
      numberOfLeadingSpaces           = lengthMacroName - lengthStrippedMacroName;

      put +numberOfLeadingSpaces macroName; /*put strips leading spaces from variable*/
    end;
  run;

  /*Run list_macros program*/
  data pgm=work.list_macros;
  run;

  proc delete data = list_macros (memtype = program);
  run;

  option notes;

%mend;

Powered by peut-publier

©2020 Matt Trzcinski