Force creation of 8.3 DOS-style filename?

I’ve put together an Applescript that creates an MS-DOS style 8.3 filename by (1) replacing characters that are not usable in MS-DOS filenames and (2) prompting the user to reduce a filename to a maximum of 8 characters in the filename itself and 3 in the filename extension.

I’ve adapted a character-replacement routine that I found in another thread, but I put together my own routine for prompting the user to reduce the length of the name to 8.3. My routine seems to work correctly, but it looks like a horrible logical mess, and I wonder if any of the experts here might be willing to make it more elegant. In fact, the whole script looks like a logical mess.

(Also, at some point, I need to add a routine to warn against using “.” more than once in the name.)

Here is the relevant part of the script. Any improvements will be very welcome.

-- create a legal MS-DOS 8.3 filename

global charChange

display dialog "Enter 8.3 filename:" default answer ""
set newName to text returned of result

set charChange to false
set tid to AppleScript's text item delimiters
set badChars to {" ", "*", "/", "\\", "+", ":", ";", "<", ">", "?", "[", "]", "|", "\""}
repeat with thisChar in badChars
	set newName to my FixName(newName, (contents of thisChar))
end repeat
set AppleScript's text item delimiters to tid

if charChange is true then
	set dlgMsg to "I have changed the filename to remove characters that cannot be used in DOS. You may accept or edit the revised name: "
	display dialog dlgMsg default answer newName
	if button returned of result is "Cancelled" then
		return
	else
		set newName to text returned of result
	end if
end if

set fullLength to (length of newName) as integer
set dotPos to (offset of "." in newName) as integer
repeat while (((dotPos is greater than 9) or ((fullLength - dotPos) is greater than 3)) and (dotPos is greater than 0) or ((fullLength is greater than 8) and (dotPos is 0)))
	set dlgMsg to "Filename and extension cannot be longer than 8.3:"
	display dialog dlgMsg default answer newName
	set newName to text returned of result
	set fullLength to (length of newName) as integer
	set dotPos to (offset of "." in newName) as integer
end repeat

on FixName(currentName, fixString)
	set AppleScript's text item delimiters to fixString
	set listName to every text item of currentName
	set AppleScript's text item delimiters to "_"
	if (listName as string) is not equal to currentName then set charChange to true
	return (listName as string)
end FixName

Many thanks for any help with this.

Hi,

this is a version which displays individual error messages for the several error cases.
The global variable charChange is not needed because the equality of the file names is checked once after the repeat loop.
The default (english) value for the Cancel button in display dialog is “Cancel” not “Cancelled”.
If the user presses the Cancel button error -128 (User Cancelled) is thrown and “ outside a try block “ the script will be aborted


set {text returned:newName} to display dialog "Enter 8.3 filename:" default answer ""
copy newName to originalName
set tid to text item delimiters
set badChars to {space, "*", "/", "\\", "+", ":", ";", "<", ">", "?", "[", "]", "|", quote}
repeat with thisChar in badChars
	set newName to FixName(newName, thisChar)
end repeat
set text item delimiters to tid

if newName is not equal to originalName then
	set dlgMsg to "I have changed the filename to remove characters that cannot be used in DOS. You may accept or edit the revised name: "
	set {text returned:newName} to display dialog dlgMsg default answer newName
end if

repeat
	set tid to text item delimiters
	set text item delimiters to "."
	set countDots to count text items of newName
	set dlgMsg to missing value
	if countDots is 1 then -- check if there is at least one dot
		set dlgMsg to "The file extension is missing (max. 3 characters):"
	else if countDots is not 2 then -- check if there is more than one dot
		set dlgMsg to "There is more than one dot character in the name:"
	else
		set {fileName, fileExtension} to text items of newName
		if length of fileName > 8 then
			set dlgMsg to "Filename is longer than 8 characters:"
		else if length of fileExtension > 3 then
			set dlgMsg to "File extension is longer than 3 characters:"
		end if
	end if
	set text item delimiters to tid
	if dlgMsg is missing value then exit repeat
	set {text returned:newName} to display dialog dlgMsg default answer newName buttons {"Edit"} default button 1
end repeat

on FixName(currentName, fixString)
	set text item delimiters to fixString
	set listName to every text item of currentName
	set text item delimiters to "_"
	return listName as text
end FixName

Stefan,

That is brilliant and clear, and it teaches me a lot about scripting. Thank you!

I should have specified that a legal MS-DOS filename can have no extension at all, and can merely be a one-to-eight-character filename. So the rule is that these are all legal:

file
filename
filename.e
filename.ext

And I also realized that I should not allow a filename with no extension to end with a dot (so “filename.” is illegal).

So I modified your code to look like this, but I suppose it could be improved again, if you have the patience and interest:


set {text returned:newName} to display dialog "Enter 8.3 filename:" default answer ""
copy newName to originalName
set tid to text item delimiters
set badChars to {space, "*", "/", "\\", "+", ":", ";", "<", ">", "?", "[", "]", "|", quote}
repeat with thisChar in badChars
	set newName to FixName(newName, thisChar)
end repeat
set text item delimiters to tid

if newName is not equal to originalName then
	set dlgMsg to "I have changed the filename to remove characters that cannot be used in DOS. You may accept or edit the revised name: "
	set {text returned:newName} to display dialog dlgMsg default answer newName
end if

repeat
        -- add test for dot as last character
	if the last character of newName is "." then set newName to (characters 1 through -2 of newName) as string
	set tid to text item delimiters
	set text item delimiters to "."
	set countDots to count text items of newName
	set dlgMsg to missing value
	if countDots is greater than 2 then -- check if there is more than one dot
		set dlgMsg to "There is more than one dot character in the name:"
	else
		set fileName to text item 1 of newName
		if length of fileName > 8 then
			set dlgMsg to "Filename is longer than 8 characters:"
		end if
		if countDots is 2 then
			set fileExtension to text item 2 of newName
			if length of fileExtension > 3 then
				set dlgMsg to "File extension is longer than 3 characters:"
			end if
		end if
	end if
	set text item delimiters to tid
	if dlgMsg is missing value then exit repeat
	set {text returned:newName} to display dialog dlgMsg default answer newName buttons {"Edit"} default button 1
end repeat

on FixName(currentName, fixString)
	set text item delimiters to fixString
	set listName to every text item of currentName
	set text item delimiters to "_"
	return listName as text
end FixName

I’d prefer this


.
	if the last character of newName is "." then set newName to text 1 through -2 of (get newName)
.