Serious First Steps In UserTalk Scripting
Prev |
Table Of Contents |
Next
Our counting program has served its purpose, introducing us to some basic features of the UserTalk language; but, as we said earlier, UserTalk isn't just a language but a way of scripting Frontier itself, and the Macintosh in general. So let's stop counting numbers and start treating rather more significant entities. We'll start by talking about files.
UserTalk provides verbs that permit us to interact with the filing system. Not only can we find out, and change, facts about a file such as its name, its type and creator codes, and so forth, but we can also read and write files. As an example, let's write a program which creates a textfile consisting of the pathnames of all the files in a given folder. Let's call it workspace.FileLister.
First, we'll ask the user what folder we are to list. We do this with the verb file.getFolderDialog, which, like dialog.getInt, takes a string prompt and an address into which the result will be placed if the user clicks OK. If the user clicks Cancel, the verb itself will evaluate to "false", so in that case we want to exit the routine. Here's a start to our routine that checks to see that we are getting the pathname of the folder properly (that is, the "msg" call is for testing purposes only, as we develop the script); try running it!:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return msg (whatFolder) fileLister ()
If we don't exit with "return" because the user clicked Cancel, "whatFolder" will contain the pathname of the folder we are to list. Now what? UserTalk provides a looping structure for situations of the type "every file in this folder". This structure, called "fileloop", requires that we designate a variable into which the pathname of each file in the folder will be placed on successive passes through the loop. It also lets us say how deeply into the nested subfolders of the given folder we want to look; let's assume that we want to look only at files in the actual folder that we choose, in which case the second parameter will be 1. So the form of our script will be:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return local (theFile) fileloop (theFile in whatFolder, 1) ??? fileLister ()
where "???" is the action, hitherto undecided, that we are to take for each pathname that shows up in "theFile". Again, just to make sure the script is working, let's list them all in the Main Window just for fun:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return local (theFile) fileloop (theFile in whatFolder, 1) msg (theFile) fileLister ()
If you run this script and choose a folder with plenty of files in it, you'll see their names zip past (rather too quickly to read) in the Main Window. What we really want to do with those names, however, is not list them in the Main Window, but write them out to a textfile. One way to do this is to gather all the names into a single string variable, and then do the writing of the file later, after the loop has terminated. UserTalk lets us use the "+" operator to "add" one string onto the end of another, that is, to concatenate strings. So let's start with an empty string, and then concatenate each file name to the end of it in the "fileloop", like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile fileLister ()
We can't test this by displaying "s" in the Main Window, because it's likely to be huge. Instead, let's put "s" into a wptext window and get a look at it that way. Create a new wptext entry in workspace; call it TestWindow. Now go back to workspace.FileLister and modify it to look like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile edit (@workspace.TestWindow) wp.setText(s) fileLister ()
And run it. It works - sort of. The filenames appear in workspace.TestWindow, but they have all been run together into an illegible mess. That's because we forgot to supply a separator between filenames. A good one would probably be a return-character. UserTalk supplies a constant, "cr", which contains a return-character; so let's modify workspace.FileLister once more:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile + cr edit (@workspace.TestWindow) wp.setText(s) fileLister ()
Run this. Ahh, much better. By the way, the two lines at the end:
edit (@workspace.TestWindow) wp.setText(s)
are typical of how UserTalk works with Frontier database objects such as wptexts and outlines. The verb wp.setText (where "wp" implies that this is a verb for working with wptexts) sets the entire text of a wptext, replacing what was there already with the contents of the string parameter passed to it; but you'll notice it doesn't specify what wptext is to be set. The answer is that there is always some database object which is "the target", the object that will be acted upon by subsequent verbs of this sort. There are several ways of causing an object to be "the target"; in this case, the call in the previous line to the verb "edit", which opens the edit window of the non-scalar object whose address is handed to it as parameter, also causes that window to be "the target".
We now know that "s" is coming out the way we want it, so it is simply a question of writing its value out as the contents of a file instead of displaying it in a wptext. Writing a file, especially a new file, requires quite a number of steps. We have to what file is to be written; then we open it, write to it, close it; plus, we should set its type and creator, so that it is seen as a TEXT file and can be double-clicked so as to open the correct word-processor.
Luckily, because this series of steps is so frequent, it is included as a script, at suites.toys.writeWholeFile. You can open this script and examine it; in our own script, we'll simply call it. So now workspace.FileLister looks like this:
on fileLister () local (whatFolder, whatListFile) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return if not file.putFileDialog("What file shall we list to?", @whatListFile) return local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile + cr toys.writeWholeFile (whatListFile, s, 'TEXT', 'ttxt', clock.now()) fileLister ()
Run this; afterwards, find the listing file you designated in the second dialog, and double-click it to open it with SimpleText. Sure enough, it contains our list of files.
Notice how we've written the type and creator codes in the call to toys.writeWholeFile, putting them in single-quotes. This indicates that these are not strings but rather string4s, a special type of "packed" string of exactly four characters used for various identifiers (not just type and creator codes, but also constants and parameter type designators in Apple events, as well as various internal identifiers in Frontier). Single-quotes are also used in Frontier to delimit an individual character, as opposed to a string that is one character long.
Now that the FileLister routine is written, you might consider modifying it in various ways. For instance, you could put a condition in the "fileloop" structure so that only a particular subset of the files is listed: those files over a certain size, or created after a certain date, or having a particular type or creator. Play with "fileloop"! Have fun.
Prev |
Table Of Contents |
Next
Text © Matt Neuburg 1997 ALL RIGHTS RESERVED
You can download a copy of this tutorial.
This Web document scripted with Frontier. Last build at 4/18/97; 10:48:18 PM.