UserLand Software
Powerful, cross-platform web scripting.
 

Strings and Files

Frontier Scripting Tutorial

About This Tutorial

What Does Frontier Do?

Keywords, Handlers, Verbs, and Calls

Loops, Variables, Parameters, and Conditionals

The Handler Rule

Returns, Addresses, and Dereferencing

Scope and With

Strings and Files

Outlines and Tables

Running, Debugging, and Getting Help

Datatypes

A Real-Life Problem

String Parsing and Substitution

Manipulating Files and Folders

Final Touches

Let's talk about files

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.

File system verbs

Frontier 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? Frontier 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 About 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.

Frontier 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 About 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. Frontier 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 Frontier works with 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 the verb file.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
   file.writeWholeFile (whatListFile, s, 'TEXT', 'ttxt', clock.now())
fileLister ()

Run this; afterwards, find the listing file you designated in the second dialog, and open it with NotePad or SimpleText. Sure enough, it contains our list of files.

Notice how we've written the type and creator codes in the call to file.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.

The type and creator codes are Macintosh-specific. The file.writeWholeFile verb ignores them on Windows, where the type is determined by the file suffix. But on Windows you may still find yourself using string4s sometimes for other purposes.

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.

PreviousNext

   

Site Scripted By Frontier © Copyright 1996-98 UserLand Software. This page was last built on 2/10/98; 1:31:29 AM. It was originally posted on 4/15/97; 8:53:23 PM. Webmaster: brent@scripting.com.

 
This tutorial was adapted for Frontier 5 by Brent Simmons, from the Frontier 4 scripting tutorial written by Matt Neuburg.