Notifications
Clear all

[Closed] SymbolicPaths struct extension

I recently had a project where I needed to easily organize all external files in predefined folders.
Then I find very cool way which enabled me to define my custom file paths using SymbolicPaths methods. I not saw any topic related to this so I decided to share my struct as extension of previously mentioned struct. To see all existing system path names try this code.

for i = 1 to symbolicPaths.numPaths() do 
(
	format "index:% PathName:% PathValue:%
" i (symbolicPaths.getPathName i) (symbolicPaths.getPathValue i)
)

In addition to these we can also define custom (user-defined) symbolic path names.

5 Replies
struct symbolicPath
(
private	
	_numUserPaths = symbolicPaths.numUserPaths,
	_addUserPath = symbolicPaths.addUserPath,
	_removeUserPath = symbolicPaths.removeUserPath,
	_isUserPathName = symbolicPaths.isUserPathName,
	_getUserPathName = symbolicPaths.getUserPathName,
	_getUserPathValue =  symbolicPaths.getUserPathValue,
	_setUserPathValue =  symbolicPaths.setUserPathValue,
	_expandFileName = symbolicPaths.expandFileName,
	_stripPathToLeaf = pathConfig.stripPathToLeaf,
	sioDIr = dotNetClass "System.IO.Directory",
	sioSOpt = dotNetClass "System.IO.SearchOption",
public
	-- add new user path or set new value for existing one
	fn newUserPath symbName filePath = 
	(
		filePath = if filepath != unsupplied do trimright filepath (@"\")
		if (count = _numUserPaths()) == 0 then _addUserPath symbName filePath else
		(
			if _isUserPathName symbName then
			(
				if (_getUserPathValue symbName) != filePath then _setUserPathValue symbName filepath else off
			)
			else _addUserPath symbName filepath
		)
	),
	
	-- collect all Symbolic User Path Names
	fn allUserSymbNames = if (count = _numUserPaths()) == 0 then #() else (for i = 1 to count collect _getUserPathName i),
	
	-- collect all File Paths
	fn allUserFilePaths = if (count = _numUserPaths()) == 0 then #() else (for i = 1 to count collect _getUserPathValue i),	
		
	-- collect all sub-directories of specifiedSymbolic Name
	fn allSubDirectories symbName topmost:off pattern:"*" = if _numUserPaths() != 0 and _isUserPathName symbName do
	(
		if sioDir.Exists(folder = _getUserPathValue symbName) do
		(
			local opt = if topmost then sioSOpt.TopDirectoryOnly else sioSOpt.AllDirectories
			sioDir.GetDirectories folder pattern opt
		)
	),
	
	-- collect all File Names of specifiedSymbolic Name
	fn allFileNames symbName topmost:off pattern:"*.*" = if _numUserPaths() != 0 and _isUserPathName symbName do
	(
		if sioDir.Exists(folder = _getUserPathValue symbName) do
		(
			local opt = if topmost then sioSOpt.TopDirectoryOnly else sioSOpt.AllDirectories
			sioDir.GetFiles folder pattern opt
		)
	),
	
	-- get Symbolic User Name by specified filepath
	fn findSymbolicUserName filePath = if (count = _numUserPaths()) != 0 do
	(
		filePath = trimright filePath (@"\")
		local symbs = for i = 1 to count collect _getUserPathValue i
		if (idx = findItem symbs filePath) != 0 then (free symbs ; _getUserPathName idx) else (free symbs ; null)
	),
	
	-- get fully qualified sub-directory name if the directory is found (this function return single string name or aray of string names)
	fn getFullSubDirPath symbName dirName = if _numUserPaths() != 0 and _isUserPathName symbName do
	(
		local path = ""
		if sioDir.Exists(_getUserPathValue symbName) do
		(
			local folders = allSubDirectories symbName topmost:off pattern:("*"+dirName+"*")
			folders = for f in folders where _stripPathToLeaf f == dirName collect f
			path = case of
			(
				(folders.count == 1): folders[1]
				(folders.count > 1): folders
				default: ""
			) ; free folders
		) ; path			
	),
	-- get fully qualified filename if the file is found (this function return single string name or aray of string names)
	fn getFullFilePath symbName fileName = if _numUserPaths() != 0 and _isUserPathName symbName do
	(
		local path = ""
		if sioDir.Exists(_getUserPathValue symbName) do
		(
			local patt = if (tmp = filterString filename ".").count == 1 then "*.*" else ("*."+tmp[tmp.count])
			local files = allFileNames symbName topmost:off pattern:patt
			local files = for f in files where MatchPattern f pattern:("*"+filename) ignoreCase:on collect f
			path = case of
			(
				(files.count == 1): files[1]
				(files.count > 1): files
				default: ""
			) ; free files
		) ; path
	),
	
	-- expand FileName using absolut path
	fn expandFileName symbName fileName = if _isUserPathName symbName and fileName != "" do
	(
		_expandFileName (symbName + "\\" + (filenamefrompath fileName))
	),
	
	-- remove if Symbolic User Path Name exists (*symbName* can be string name or array of string names)
	fn removeUserPathName symbName = if _numUserPaths() != 0 do
	(
		if isKindOf symbName Array then
		(
			local validNames = for n in symbName where _isUserPathName n collect n
			if validNames.count != 0 do (for n in validNames do _removeUserPath n ; free validNames)
		)
		else if _isUserPathName symbName do _removeUserPath symbName
	),
	
	-- remove Symbolic User Path Name by specified filepath
	fn removeByFIlePath filePath = if (count = _numUserPaths()) != 0 do
	(
		local symbs = for i = 1 to count collect _getUserPathValue i
		if (idx = findItem symbs filePath) != 0 then (free symbs ; _removeUserPath idx) else (free symbs)
	),
	
	-- remove all Symbolic User Paths
	fn removeAll = (if (count = _numUserPaths()) != 0 do for i = count to 1 by -1 do _removeUserPath i)
)

This is example how to use it

symbolicPathsExt = symbolicPath()
-->(symbolicPath)
symbolicPathsExt.removeAll()
symbolicPathsExt.newUserPath "$myTempDir" "C:\	emp"
symbolicPathsExt.allUserSymbNames()
-->#("$myTempDir")
symbolicPathsExt.allUserFilePaths()
-->#("C:	emp")
symbolicPathsExt.allSubDirectories "$myTempDir"
-->#("C:	emp	est", "C:	emp	est
ew")
symbolicPathsExt.allFileNames "$myTempDir"
-->#("C:	emp\contosoBooks.xml", "C:	emp\Readme.txt", "C:	emp	estLinq.xml", "C:	emp	est\install.msi", "C:	emp	est
ew\bgaLight.jpg", "C:	emp	est
ew\logo.psd")
symbolicPathsExt.findSymbolicUserName @"C:	emp"
-->"$myTempDir"
symbolicPathsExt.getFullSubDirPath "$myTempDir" "new"
-->"C:	emp	est
ew"
symbolicPathsExt.getFullFilePath "$myTempDir" "testLinq.xml"
-->"C:	emp	estLinq.xml"
symbolicPathsExt.expandFileName "$myTempDir" "d:\work\recent\particle_test.max"
-->"C:	emp\particle_test.max"
symbolicPathsExt.removeUserPathName "$myTempDir" -- or symbolicPathsExt.removeUserPathName #("$myTempDir", "$workDir", "$anyDir")
symbolicPathsExt.removeByFilePath @"C:	emp"

I also thought to put method where the user will be able to save and load all collected symbolic paths, filepaths and filenames to *.ini, *.txt or *.xml file
Anyway i’d like to see if anyone has any other ideas about extension of this struct.

 JHN

If symbolic pathnames could be used inside bitmap loaders etc, that would be supercool.
You could easily repath all project external files by redeclaring a custom Symbolic path.

I don’t see a great use of it at this point, besides building your own project convention. But it will never leave the maxscript realm at this point.

-Johan

1 Reply
(@gandhics)
Joined: 11 months ago

Posts: 0

I agree.
When I saw this post, I was super excited, then I found out that I can use this only in maxscript. Well… in maxscript I don’t even need this. I can just make a function to make what ever path I need.

All we need is a escape character for maxscript.
Since the following characters are illegal to use in pathname.
< > : “/ \ | ? *
Max dev could make one of them as scape character for maxscript.

For example, if I set path like this.
c: emp*(sysinfo.username)\whatever.jpg
3ds max could read as
c: emp\ceun\whatever.jpg

Sure this is not perfect solution. Anyway don’t blame me I not work for AD
Happy New Year to all of you!