Abstract

a command-line interface to the F-Script interpreter, including useful enhancements for Perl/Python - like processing of strings and files. Current Version 2.2, released 2008-10-16. Download binary here, Download source here.

Sections: Using fscript | Classes and Categories | Other Enhancements | Dependencies | F-Script compared to Other Languages | Downloads | Installer Files | Known Bugs | Legal | List of Additional Classes and Categories


Description

fscript is a program that allows F-Script scripts to be run from the command line, and to can also present an interpreter prompt in a shell, rather than requiring a GUI program. fscript also provides some useful classes and methods that make the language more appropriate for general scripting tasks, such as line-oriented input/output, regular expressions, and a library importing system.

In this documentation, fscript is used to refer exclusively to the command-line program, while "F-Script Interpreter" refers to the internal FSInterpreter object that actually does the real work of running the script.

Using fscript

The fscript program is installed in /usr/bin, so we may use it directly to run scripts:

$ fscript myscript.fs

However, other scripting languages like Perl and Python allow a "shebang" line at the beginning of the script file to tell the shell which interpreter program to use, so that the script can be executed directly. It would be nice to be able to do the same thing with F-Script scripts; however, #!/usr/bin/fscript is not a comment in F-Script, as it is in those other languages, and will cause a syntax error. As a work-around, when fscript loads a file - either as the main script or as a library with sys import: - it looks for a shebang command on the first line of the script file. If the first line is exactly "#!/usr/bin/fscript", the fscript strips this line before handing the script's contents to the F-Script interpreter.

If no filename is provided, fscript will open an interactive interpreter prompt. Type sys exit to quit.

Currently, fscript does not use any command-line switches to change behavior, although it may in the future.

fscript currently does only links to the Foundation Kit, so scripts that are run with it cannot use any classes from the Application Kit, and thus cannot put up graphical applications. This is a planned addition for the future.



Classes and Categories

The fscript program has several built-in classes and categories that provide common scripting-language functionality, such as line-oriented file handles, regular expressions, and Perl-like looping constructs. These additions are listed at the end of this document.

Other Enhancements

fscript traps all syntax errors and other exceptions that are not handled by the script itself. Unlike the regular F-Script interpreter, fscript reports both the line number and character number of the error's location, rather than just the offset into the script text.

fscript adds several important methods to the global sys object::

in
Returns an FSFile object representing standard input
out
Returns an FSFile object representing standard output
err
Returns an FSFile object representing standard error
args
Returns an array containing the command-line arguments, if any, that were supplied to the script. In the manner of Perl's @ARGV array, the name of the script is not included as the first element.
scriptname
Returns a string containing the name of the main program, which will not be the name of the currently executing script if it was pulled in with import:
help
Returns an object that offers help on several features of the interpreter. Currently available help topics: import, version, quit, and frameworks


In versions prior to 2.2, these were global variables. To reduce namespace pollution, they have been moved into the sys object.



Dependencies

fscript requires the F-Script framework to be installed in /Library/Frameworks. As of version 2.0, the fscript executable has the PCRE library compiled in, so the old AGRegex package is no longer necessary. If you are replacing an older version of fscript, you can remove this package.



F-Script and other languages

One of F-Script's advantages is that the excellent classes from the Cocoa platform are available. Below is the bash shell script used to generate the HeaderDoc for this project:

#!/bin/bash
# This file compiles headerdoc for all the headers in the project, then compiles # the top-level headerdoc # The script caches file modifications times in the header_mod_times file to # avoid unnecessary reprocessing
MOD_FILE=header_mod_times
# rebuild all files if desired if [ "$1" = clean ]; then rm -f "$MOD_FILE" fi
# create a file to cache modification times if [ ! -f "$MOD_FILE" ]; then touch "$MOD_FILE" fi
OUTPUT_DIR=Documentation
# We'll create a symlink to the project-specific HeaderDoc config file CONFIG_LOC=~/Library/Preferences/com.apple.headerdoc2HTML.config
if [ -f "$CONFIG_LOG" ]; then mv "$CONFIG_LOC" "$CONFIG_LOC.temp" fi
ln -s "$PWD/Documentation/headerdocconfig" "$CONFIG_LOC"
HEADERS='ArrayUtil FSSystemUtility FSNSNumberMod FSFile StringSprintf StringRegex FSNSMutableDictionary FileTest BlockForeach'
for HEADER in $HEADERS; do FILE_MOD_TIME=`stat -f "%N %m" "$HEADER.h"` FILE_MODIFIED=`grep "$FILE_MOD_TIME" "$MOD_FILE"` if [ -z "$FILE_MODIFIED" ]; then echo headerdoc2html -H -o $OUTPUT_DIR/ "$HEADER.h" headerdoc2html -H -o $OUTPUT_DIR/ "$HEADER.h" fi done
stat -f "%N %m" *.h > "$MOD_FILE"
headerdoc2html -H -o $OUTPUT_DIR/ "fscript.hdoc"
gatherheaderdoc "$OUTPUT_DIR"
# get rid of the temp config file and put the old one back if any rm -f "$CONFIG_LOC"
if [ -f "$CONFIG_LOG.temp" ]; then mv "$CONFIG_LOC.temp" "$CONFIG_LOC" fi


Note how it caches modifying times by using stat, grep, I/O redirection, and other hacks.

Here's an equivalent program in F-Script, using some of the additional methods and features from the command-line program:

#!/bin/fscript
"
This file compiles headerdoc for all the headers in the project, then compiles
the top-level package headerdoc.
The script caches file modifications times in the file header_mod_times to 
avoid unnecessary reprocessing
"
modFileName := 'header_mod_times'.
"list of header names - use F-Script array messaging to append .h extension" headers := { 'ArrayUtil', 'FSSystemUtility', 'FSNSNumberMod', 'FSFile', 'StringSprintf', 'StringRegex', 'FSNSMutableDictionary', 'BlockForeach', 'FileTest' } @ ++ '.h'.
outputDir := 'Documentation'.
configLoc := '~/Library/Preferences/com.apple.headerdoc2HTML.config' stringByExpandingTildeInPath.
"if the mod times file exists and we were not told to run clean, use it" "otherwise, use a blank file" clean := (args count > 0) ifTrue:[ (args at:0) = 'clean'] ifFalse:[ false ].
oldModTimes := ((filem test_f:modFileName) & (clean not)) ifTrue:[ NSDictionary dictionaryWithContentsOfFile:modFileName. ] ifFalse:[ NSDictionary dictionaryWithObjects:(NSDate distantPast enlist:(headers count)) forKeys:headers. ]. newModTimes := NSMutableDictionary dictionary.
"move existing config file out of the way and replace with a link to our file" tempConfigLoc := configLoc ++ '.temp'. (filem fileExistsAtPath:configLoc) ifTrue:[ filem movePath:configLoc toPath:tempConfigLoc handler:nil. ]. filem createSymbolicLinkAtPath:configLoc pathContent:'Documentation/headerconfig'.
"For each header file, check to see if it has been changed since the last time we ran this script; if so, regenerate documentation files" updateModTimes := NO. [ :header | |fileModTime| fileModTime := filem test_m:header. ((oldModTimes objectForKey:header) < fileModTime) ifTrue:[ "run headerdoc on the modified header file" out println:('headerdoc2html -H -o ' ++ outputDir ++ '/ ' ++ header). sys execNoOutput:'headerdoc2HTML' args:{'-H', '-o', outputDir++'/', header}. updateModTimes := YES. ]. newModTimes setObject:fileModTime forKey:header. ] value: @ headers.
"Save new modification times" saveModTimes ifTrue:[ newModTimes writeToFile:modFileName atomically:YES. ].
"generate program header" runh2h value:'fscript.hdoc'.
"create document structure" sys execNoOutput:'gatherheaderdoc' args:{outputDir}.
"move existing config file back" (filem test_f:tempConfigLoc) ifTrue:[ filem movePath:tempConfigLoc toPath:configLoc handler:nil. ].


Not that much longer, and a lot more readable! It also uses actual data structures like dictionaries and arrays, and stores them in a property list, avoiding potential bugs and security problems from shell expansion and parsing.



Downloads

  • Download the F-Script package (including framework, GUI interpreter, F-Script Anywhere, and other tools): download
  • fscript command-line program installer: download
  • Source code for fscript: download
  • The FSClass framework, which lets you write classes directly in F-Script (useful with the sys import: method): download




Installed Files

The fscript installer installs three files: the framework FSRegex7 (source and separate binary available here) in /Library/Frameworks, the fscript executable in /usr/bin, and a manpage in /usr/share/man/man1.



Version History

2008-01-10
Version 2.2
  • Updated to be compatible with F-Script 2.0 alpha 6
  • PCRE updated to version 7.8
  • The global variables in, out, err, scriptName, and args have been turned into methods on the sys object
  • The global variable filem has been removed


2008-01-10
Version 2.0
  • Updated to run on Mac OS X 10.5
  • Now supports running in 64-bit mode
  • Now requires F-Script 2.0
  • The regular expression library has been integrated into the tool itself; the AGRegex framework is no longer required as a separate library. The AGRegex and AGRegexMatch classes have been renamed FSRegex and FSRegexMatch
  • Improved the regular expression matching category on NSString
  • PCRE engine updated to version 7.4
  • "help version" and the -v flag now print the active machine architecture
  • The "help" command now supports an additional option, "help frameworks", which will list the identifier and version of all loaded bundles and frameworks
2007-08-16
Version 1.6
  • Fixed a bug that made command-line arguments inaccessible
2007-08-16
Version 1.5
  • Add a help object with information on importing files, quitting the interpreter, and versions of F-Script, the interpreter, and the PCRE library
  • Clarified messages for 'file not found' errors
  • Added '-v' (version) and '-c' (check syntax) command-line options
  • The interactive interpreter can now be quit by typing 'Control-D' as well as sys exit.
  • FSRegex7 framework updated to PCRE 7.2
  • Included several useful scripts in the Library directory (requires FSClass)
  • Fixed formatting errors in -NSString sprintf: and -FSFile printf:withValues:
  • Miscellaneous bug fixes
2007-02-13
Version 1.2
  • Added +dictionaryWithPairs: and +dictionaryWithFlatPairs: to NSDictionary
  • Fixed a bug in 'sys import:'
  • Added bold-faced prompts to compatible ANSI and color-xterm terminals
2007-02-07
Version 1.1
  • Fixed a bug that would cause 'sys execShell:' to crash
  • Added interactive interpreter
2007-01-21
Version 1.0
  • Initial release




Bugs

None known.



Legal

The fscript command-line program and libraries are made available under the GNU General Public License version 2:

License for fscript

fscript - command line interface and enhancements for F-Script
Copyright (C) 2007 Andrew Weinrich
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (file COPYING) for more details.




fscript incorporates some third-party code, the licenses for which are reproduced here:

Licence for PCRE

As of fscript 2.0, the tool directly incorporates version 7.4 or later of the Perl-Compatible Regular Expression Library. The source code to the library is included with the source disk image.

           Copyright (c) 1997-2007 University of Cambridge
----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------


License for AGRegex

The Objective-C wrapper around the PCRE library for fscript was derived from the AGKit framework, particularly the AGRegex classes.
   Copyright (c) 2002 Aram Greenman. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License for readln

The code for the FSFile readln method was adapted from the class IOSocketLineReader of the Halime newsreader application:

//
//  ISOSocketLineReader.m
//  Halime
//
//  Created by iso on Mon May 21 2001.
//  Copyright (c) 2001 Imdat Solak. All rights reserved.
//
Halime status 1.0rc2b
This is the source code of Halime 1.0rc2b. The source code is delivered to you under the GPL - GNU General Public License (s. COPYING).
You may NOT use it to create any product called "Halime" or which name resembles "Halime" in any way.
Otherwise, you are permitted to do with the code whatever you want.
Imdat Solak November 4th, 2003 -------------------------------------------------------------------------------





Classes

FSFile
FSRegex
FSRegexMatch

Categories

Block(BlockForeach)
NSDictionary(FSNSDictionaryPairs)
NSNumber(FSNSNumberMod)
FSSystem(FSSystemUtility)
NSFileManager(FileTest)
NSString(StringRegex)
NSArray(ArrayUtil)
NSMutableDictionary(FSNSMutableDictionary)
NSString(StringSprintf)