Serious First Steps In UserTalk Scripting
by Matt Neuburg
Author of the book Frontier: The Definitive Guide

Prev | TOC | Next


Manipulating Files and Folders

Onward and upward

We left off in the previous chapter with our routine, workspace.buildSite, worked out to the point where we were ready to write each piece of text out to disk as new HTML file.

The last three lines are only for testing purposes, so remove them. In their place we want to write out "s" as a new textfile. We know how to do this, using file.writeWholeFile(); the question is where to do it. We need a place to put the files, and we need a name for each one.

Working with folders

As for the place, let's create a new folder inside the AmelioWeb folder. We'll call it "Website".

We can calculate its pathname in the same way we calculated the pathname for "infolder"; and, to go with it, let's call the variable in which we store the result of the calculation "outfolder". Right after the "local" line where we declared "infolder", we'll insert a line:

local (outfolder = folder + "Website" + file.getPathChar())

We need to make sure that the folder designated by "outfolder" really does exist; if it doesn't, we need to create it.

Consulting the documentation, we discover a verb file.sureFolder(), which creates a folder (and all its containing folders) if it doesn't exist. So we'll say:

file.sureFolder (outfolder)

Also, in case the folder does already exist, it might be because we've done the demo before, perhaps during testing. In that case we'd like to clean it out fresh, so that only the files we add during the present run of the routine will be there.

This sounds like a job for file.emptyFolder(), which empties out a named folder. (You can study its script; it's very easy to understand.) So we'll call it:

file.emptyFolder (outfolder)

File names

So much for the place to put the files. What about a name for each file?

Well, each file in "Source Files" is named with a suffix ".txt". On the other hand, we will be creating HTML files, whose names it makes sense to end with a suffix ".html" so they can be served over the Web. Our most economical course is to change the names by replacing ".txt" with ".html".

For each HTML file we make, let's call the filename "fname" and the full pathname for that file "outfile".

Clearly, "outfile" is simply "outfolder" plus "fname". Now, how will we get "fname"?

What we're starting with is "infile"; but "infile" includes the whole pathname, leading into the "Source File" folder. We want to strip this off, leaving just the name of the file itself; then we want to transform the name by replacing ".txt" with ".html". That's "fname".

We know how to perform the replacement; we can use string.replaceAll(), or perhaps just string.replace() (which replaces just one occurrence); it makes no difference since there's just one occurrence to replace.

How will we strip off the first part of the pathname, leaving just the name of the file? Lo and behold, there's a verb file.filefrompath() for just this purpose. UserTalk certainly includes some convenient verbs, doesn't it?

We need to do all this for every file we read in, so it goes in the "fileloop" construct; let's put it right after the line where we read in the file and assign it to "filetext". We can say:

    local (fname = file.filefrompath (infile))
    fname = string.replace (fname, ".txt", ".html")
    outfile = outfolder + fname

Writing files

Now we are ready to write out "s" with a call to file.writeWholeFile().

This takes a lot of parameters, so let's be sure we have them all straight. We need the pathname to write to: that's "outfile". We need the text to be written; that's "s".

On Mac OS, we need a file type code to be given to the new file; this is a textfile, so it's the string4 'TEXT'.

We need a creator code for the new file too; what application should "own" this file? It could be any application, really; neither our browser nor a Web server is going to care who created the file, provided it's a textfile. But for our own convenience, it might be nice to have the creator be our browser, so use either 'MSIE' or 'MOSS' depending which browser you prefer.

Finally, we need a creation date-time; there's no need for this to be anything but the actual moment of creation, which we can determine with a call to clock.now(). Thus, if you use Internet Explorer:

    file.writeWholeFile (outfile, s, 'TEXT', 'MSIE', clock.now ())

Our program now looks like this:

html.data.adrpagetable = @websites.["#data"]
local (folder)
if not file.getFolderDialog \
    ("Where is the AmelioWeb folder?", @folder) {return}
local (templatetext = string (file.readWholeFile (folder + "template.html")))
local (infolder = folder + "Source Files" + file.getPathChar())
local (outfolder = folder + "Website" + file.getPathChar())
file.sureFolder (outfolder)
file.emptyFolder (outfolder)
local (infile, filetext, title, subtitle)
on popline()
    local (s)
    s = string.NthField (filetext, cr, 1)
    filetext = string.delete (filetext, 1, string.length(s) + 1)
    return s
fileloop (infile in infolder, 1)
    filetext = string (file.readWholeFile (infile))
    filetext = string.replaceAll (filetext, lf, "")
    title = popline (); popline (); popline (); popline ()
    subtitle = popline (); popline ()
    local (s = templatetext)
    s = string.replaceAll (s, "<<title>>", title)
    s = string.replaceAll (s, "<<subtitle>>", subtitle)
    s = string.replaceAll (s, "<<bodytext>>", filetext)
    s = html.processMacros (s)
    local (fname = file.filefrompath (infile))
    fname = string.replace (fname, ".txt", ".html")
    outfile = outfolder + fname
    file.writeWholeFile (outfile, s, 'TEXT', 'MSIE', clock.now ())

Trying it out

The moment of truth has come. Let's run the program and see what we get. (Hmm, it's sort of dull waiting around for it to process the files and not knowing what stage it's at; we really must put in some feedback later on.)

When it's all finished, go in the Finder [Microsoft Explorer] to the AmelioWeb folder, open the Website folder, pick a file, any file, and double-click it to inspect it in the browser.

Gee, it's beautiful! There's only one minor problem; there are three pictures that are supposed to appear, and they don't.

Examining the "Website" and "Source Files" folders, and looking at the source of our HTML file, we see why this is. The IMG tags use relative URLs; they assume a folder "images" in the same folder as the Web page. That folder is in "Source Files", not in "Website". Clearly, as we create the HTML files, we also need to copy the "images" folder and its contents across from "Source Files" to "Website".

We could do this explicitly as a one-time copy, but let's create a more general solution so that our program remains a powerful, flexible utility. We'll make a rule that any files in "Source Files" are assumed to be email textfiles and will be transformed into HTML, but any folders in "Source Files" are assumed to be other supplementary material and will be copied across unchanged.

To implement this, we need our "fileloop" to include both files and folders as candidates for "infile", deciding what to do based on what type it encounters.

At the moment, though, our "fileloop" is ignoring folders entirely; "infile" can never be a folder. A careful reading of the DocServer entry for "fileloop" shows why this is: the way to get "fileloop" to include folders among the pathnames fed to the loop is to omit the second parameter altogether.

Then, we find, there's a verb file.isFolder() which will tell us whether we're seeing a file or a folder, and a verb file.copy() that will copy a folder and its contents.

So, now the "fileloop", with the order of things slightly revised, looks like this:

fileloop (infile in infolder)
    local (fname = file.filefrompath (infile))
    msg(fname)
    if file.isFolder (infile)
        file.copy (infile, outfolder + fname)
    else
        filetext = string (file.readWholeFile (infile))
        filetext = string.replaceAll (filetext, lf, "")
        title = popline (); popline (); popline (); popline ()
        subtitle = popline (); popline ()
        local (s = templatetext)
        s = string.replaceAll (s, "<<title>>", title)
        s = string.replaceAll (s, "<<subtitle>>", subtitle)
        s = string.replaceAll (s, "<<bodytext>>", filetext)
        s = html.processMacros (s)
        fname = string.replace (fname, ".txt", ".html")
        outfile = outfolder + fname
        file.writeWholeFile (outfile, s, 'TEXT', 'MSIE', clock.now ())

We run the revised routine, and double-click an HTML file to examine it in the browser. The images are there.

Adding feedback

While we're revising, let's also put in some feedback so that our routine is a little more interesting and informative for the user to watch. We'll make this feedback particularly flashy, because we want our UserTalk prowess to amaze our friends and astound our enemies: we'll use Frontier's ability to drive other applications to get our browser to show each HTML file as it is created.

The simplest way to do this is with the verbs in suites.webbrowser, because they don't care which browser we're using (plus, their names and syntax are fairly human). To the end of the "fileloop" we'll simply add:

        webbrowser.openDocument (outfile)

And just before the "fileloop", we'll say:

webbrowser.bringToFront ()

If we make sure the browser is running and then run our routine, we get a nice, impressive show, as each page in turn is created and rendered.

It remains only to add the code that creates a table-of-contents page linking to each HTML file. That's for our next (and final!) chapter.


Prev | TOC | Next

All text is by Matt Neuburg, phd, matt@tidbits.com.
For information about the book Frontier: The Definitive Guide, see my home page:
http://www.tidbits.com/matt
All text copyright Matt Neuburg, 1997 and 1998. ALL RIGHTS RESERVED.
No one else has any right to copy or reproduce in any form, including electronic. You may download this material but you may not post it for others to see or distribute it to others without explicit permission from the author.
Downloadable versions at http://www.ojai.net/matt/downloads/scriptingTutorial.hqx and http://www.ojai.net/matt/downloads/scriptingTutorial.zip.
Please do not confuse this tutorial with a certain other Frontier 5 tutorial based upon my earlier work.
This page created with Frontier, 2/11/2000; 6:59:01 PM.