/* The following code is used to recursive traverse a block */
/* of code and extract all the symbols present in that code. */

typedef struct {
 SEXP	ans;
 int	UniqueNames;
 int	IncludeFunctions;
 int	StoreValues;
 int	ItemCounts;
 int	MaxCount;
} NameWalkerData;

NameWalkerData *nameData;

static void namewalk(SEXP s)
{
    int i, j, n;
    switch(TYPEOF(s)) {
    case SYMSXP:
	if(nameData->ItemCounts < nameData->MaxCount) {
	    if(nameData->StoreValues) {
		if(nameData->UniqueNames) {
		    for(j=0 ; jItemCounts ; j++) {
			if(STRING_ELT(nameData->ans, j) == PRINTNAME(s))
			    goto ignore;
		    }
		}
		SET_STRING_ELT(nameData->ans, nameData->ItemCounts, PRINTNAME(s));
	    }
	    nameData->ItemCounts += 1;
	}
    ignore:
	break;
    case LANGSXP:
	if(!nameData->IncludeFunctions) s = CDR(s);
	while(s != R_NilValue) {
	    namewalk(CAR(s));
	    s = CDR(s);
	}
	break;
    case EXPRSXP:
	n = length(s);
	for(i=0 ; iIncludeFunctions = asLogical(CAR(args));
    if(nameData->IncludeFunctions == NA_LOGICAL)
	nameData->IncludeFunctions = 0;
    args = CDR(args);

    nameData->MaxCount = asInteger(CAR(args));
    if(nameData->MaxCount < 0 || nameData->MaxCount == NA_INTEGER)
	nameData->MaxCount = 0;
    args = CDR(args);

    nameData->UniqueNames = asLogical(CAR(args));
    if(nameData->UniqueNames == NA_LOGICAL)
	nameData->UniqueNames = 1;

    nameData->StoreValues = 0;
    nameData->ItemCounts = 0;
    namewalk(expr);
    savecount = nameData->ItemCounts;

    nameData->ans = allocVector(STRSXP, nameData->ItemCounts);

    nameData->StoreValues = 1;
    nameData->ItemCounts = 0;
    namewalk(expr);

    if(nameData->ItemCounts != savecount) {
	PROTECT(expr = nameData->ans);
	nameData->ans = allocVector(STRSXP, nameData->ItemCounts);
	for(i=0 ; iItemCounts ; i++)
	    SET_STRING_ELT(nameData->ans, i, STRING_ELT(expr, i));
	UNPROTECT(1);
    }

    return nameData->ans;
}

Duncan Temple Lang <duncan@research.bell-labs.com>
Last modified: Wed Dec 20 12:26:28 EST 2000