program whereis, rclass
*! v1.4 mantains a directory of external files or folders 10sep2016 rev 17feb2020
	version 14
	args name location
	// why am i storing this is in a macro?
	mata whereis(`"`name'"', `"`location'"') // stores location in local location
	if `"`name'"' != "" {
		display as text `"`location'"'
		return local `name' `location'
	}
end

mata:
	void whereis(string scalar name, string scalar location) {
		real scalar pos, col, fh, retrieve, i
		string scalar dirpath, adopath, entry
		string vector dir
		dir = J(0, 1, "")

		// get or create whereis directory
		dirpath = findfile("whereis.dir")
		if(dirpath != "") {
			dir = cat(dirpath)
		}
		else {
			adopath = findfile("whereis.ado")
			dirpath = usubinstr(adopath, ".ado", ".dir", 1)
		}

		// list all resources
		name = ustrtrim(name) //!
		if (name == "") {
			if (length(dir) < 1) {
				printf("{text}No resource locations have been stored with {bf}whereis{sf}\n")
			}
			else {
				//printf("{text}File locations saved with with {bf}whereis{sf}:\n")
				listf(dirpath)
			}
			return
		}

		// retrieve location
		pos = lsearch(dir, name)
		retrieve = location == ""
		if(retrieve) {
			if(pos < 1) {
				errprintf("{txt}location of %s has not been stored with {cmd:whereis}\n", name)
				errprintf("{txt}type {cmd:help whereis} or click {help whereis} for instructions\n")
				exit(601)
			}
			col = ustrpos(dir[pos], " ")
			location = usubstr(dir[pos], col + 1, .)
		}

		// check location
		if(!fileexists(location) & !direxists(location)) {
			errprintf(`"file or folder "%s" not found\n"', location)
			exit(601)
		}
		st_local("location", location)

		// store location
		if(!retrieve) {
			entry = name + " " + location
			if(pos < 0) {
				dir = dir \ entry
			}
			else {
				dir[pos] = entry
			}
			if(fileexists(dirpath)) unlink(dirpath)
			fh = fopen(dirpath, "w")
			for(i = 1; i <= length(dir); i++) {
				fput(fh, dir[i])
			}
			fclose(fh)
		}
	}
	// linear search in whereis directory
	real scalar lsearch(string vector lines, string scalar target) {
		real scalar i, m
		string scalar key
		for(i = 1; i <= length(lines); i++) {
			m = ustrpos(lines[i], " ")
			key = m > 1 ? usubstr(lines[i], 1, m-1) : lines[i]
			if(key == target) return(i)
		}
		return(-1)
	}
	// list contents of text file
	void listf(string scalar filename) {
		string vector lines
		real scalar i
		lines = cat(filename)
		for(i = 1; i <= length(lines); i++) {
			printf("{text}%s\n", lines[i])
		}
	}
end

exit