QEF home page

Chapter 9: Qsg: The Principal QEF Script Generator

The Guide's Table of Contents Previous Chapter Bottom Of Page Next Chapter

What qsg is, how it works, command-line options, the scripting language and the library.


Although any arbitrary shell pipeline can be used as a script generator, the primary ones used are qsg and qefdirs. The qefdirs utility is used for multiple directories, and qsg is used almost all other times. qsg uses a library of pre-written scripts which address most of the common tasks performed in a software project. However, since a majority of qeffiles contain a qsg script after the Begin line, some knowledge of the qsg scripting language will be necessary. Chapter 7.5 introduced the basic facilities used in qeffiles. This chapter covers qsg and its associated tools and files in much more detail, although, full detail will require consulting the x-qsg database and the various qsg manual pages.

9.1) What Qsg Is and How It Works

qsg is several things at once. First and foremost, it is a script generator used to create mimk or make files or shell scripts. Beyond that, qsg is a small programming language that can be used for a variety of applications such as this document, xfig diagrams, the vci interface, and small programming exercises such as Scientific American puzzles and other such problems.

Using qsg on simple files is probably the best way to learn it, as in:

    % cat > tmp
    if @argv~v
	return No arguments specified
    fi
    >Arguments: @argv
    ^D
    % qsg -f tmp
    No arguments specified
    % qsg -f tmp hi there
    Arguments: hi there
You can try out the qsg standard library scripts directly from the command shell, as in:
    % qsg -c hanoi 5
    1:	move ring 1 from this one to that one
    2:	move ring 2 from this one to over there
    3:	move ring 1 from that one to over there
    4:	move ring 3 from this one to that one
    ...
    % qsg -c commands example.c
    #include mimkvars.qh
    #include	deps.qh
    
    #define _Main_ example
    Objects:V:	example.o
    example.o:P: _S_(example.c) _Touch_(cc)
    	_T_cc -c _F_cc _F_cc[example.c] _F_cc_c _F_cc_c[example.c] \
	    _Optimize_(example.c) _Threads_(example.c) \
	    _CcFlags_(example.c) _D_cc _D_cc[example.c] \
	    _InclFlags_() _A_(example.c)
    ...
    ...
qsg has a variety of applications. For example, this guide itself is written in qsg using the html.qsl qsg library -- see x-html. It is also used to process the PostScript files to insert page footers. vci, the generalized interface to version control systems, is implemented using qsg libraries, and qmsdev, which generates Microsoft Developer's Studio project files, is yet another qsg variant. However, qsg's primary application is to convert qeffiles' scripts into the input for the back-end such as mimk or qsh.
A Typical qeffile

Every directory in which a construction occurs must have an associated file called qeffile (or qeffile2). The part of that file that follows the Begin line, is usually a qsg script. Everything that applies to standard qsg scripts applies also to the script portion of a qeffile.

The most common qeffile looks something like this:

    Begin

commands @argv
When the Begin line does not have arguments, the value of the @DefaultBeginLine is used. If it is not defined, "qsg --M" is used. Typically, fifty percent of qeffiles use the default value.

The --M argument specifies that the basenames of the directory's source files -- stored in srclist._ -- are to be assigned to the qsg variable argv, and qef pre-processor #srcmap directives for the sources are output (see --M(x-qsg)) commands is a qsg library routine. The variable argv is the list of arguments to the qsg script. For the qsg script commands, each argument is processed according to its suffix. This script compiles each source file in the current directory into an executable. Scripts to build a library or to construct a program from all the files in the current directory are almost as simple.
Note:Chapter 7.5: The Construction Script presents an extensive discussion of the use of qsg in construction scripts and describes the 10 most commonly used scripts such as commands, program, and finstall.

9.2) Qsg Tools and Libraries

The qsg components of the QEF product consist of the following tools and files:

qsg The general-purpose script generator, with a built-in compiler and interpreter.
lib/qsg/std.qsl Archive of standard qsg scripts in compiled form. qsg and qsgdump search this library for requested scripts. Additional libraries, such as a project specific library, can be created as required.
lib/qsg/*.qsl There are a variety of additional qsg libraries provided in the <qtree>/lib/qsg directory. These are:
ant.qslScript to generate ant input files.
cvs.qsl vci library to interface to CVS.
dtree.qsl Scripts to process non-product Q-Tree tools, support, and testing processes used within the Q-Tree itself. For a list of functions use: x-qsg --L \*dtree_qsl.
html.qsl HTML functions as used to create this guide. For a list of functions use: x-html --L.
misc.qsl User contributed scripts provided as examples or starting points for creating your own scripts. Not supported. For a list of functions use: x-qsg --L \*misc_qsl.
p4.qsl vci library to interface to perforce.
qmsdev.qsl Contains a script that generates a Microsoft Visual Studio compatible project file. Script is invoked by qmsdev.
rcs.qsl vci library to interface to RCS.
rcsupd.qsl Scripts to manage updates from remote development site. Not supported.
sccs.qsl vci library to interface to SCCS.
vci.qsl Subroutines used by the other vci libraries.
xfig.qsl Scripts to generate xfig objects.
xppt.qsg Scripts to generate presentation slides via xfig for those people who cannot or will not use power point.

To get a listing of the scripts provided by a particular library use:

    % qsgdump -L -llib -l-N
The --l-N flag is to suppress the automatic loading of the standard library and any libraries specified by @QsgLibs. To view the source for any script within a library, use:
    % qsgdump -S -llib script
To see a script's summary, use --X instead of --S.
qsgcomp Compiles its argument script and outputs object code. It is used to create object files put into script library.
qsgdump Compiles argument scripts (if necessary) or extracts from library and dump code (by default), summary (--X flag), or source (--S flag).
x-qsg An eXplanatory database describing features of the qsg system. To retrieve a list of the major items in the database use:
    % x-qsg
    x-qsg : qsg and its support library eXplanatory D.B.
    
	   qsg-intro : introduction to qsg
	   qsg-tools : qsg tools and files
	       qsg-M : that qsg -M flag
       qsg-variables : variables in qsg
	        argv : arguments to a qsg script
 <Q>/lib/qsg/std.qsl : the standard qsg library
	 qsg-sfxmaps : qsg mapping of suffix to script controls
	 qsg-scripts : list of standard qsglib scripts
	   qsg-input : qsg input conventions and the @ escape
	  qsg-syntax : qsg keywords and syntax
	   tilde-ops : the qsg postfix ~ list operators
       qsg-functions : list of all qsg-functions
	 qsg-opcodes : list of qsg opcodes and their interpretation
    
    See also: qsg qsg(1) qsgdump qsgcomp qvrs x-qsg x_db
To retrieve the information of a particular item, such as qsg-M, use:
    % x-qsg qsg-M
    qsg-M : that qsg -M flag
    
    As has been mentioned in qsg-intro, about 50% of the Begin
    lines are:
    
    	Begin qsg -M

    or its equivalent:

	Begin
    
    ...
Appendix F: The QEF Specialist's Reference Card contains four items extracted from x-qsg for quick reference. These are:

9.3) Command Syntax

The synopsis of the qsg command is:

    qsg [qsg-options] [--] [script-options]
The "----" is required if the first script option begins with a `--'. The command:
    % qsg -x
    qsg [-xVMmqrST] [-C[mp]] [-a file] [-f script]
	[-o outfile] [-l lib] [[-[-c]] args]
    
    the qef script generator interpreter
    
    -x		display this explanation
    -V		output version information
    -M		equivalent to `-m -a srclist._' -- see -r
    ...
will output a brief description of all the flags and options.

Typically, qsg is called with one of the following options:
--M construct the product from the list of source files (srclist._)
--f <file> interpret the named file
--c <command> execute the specified command

The qsg --M command suffices for the majority of software constructions. Using the list of source files (usually the sls produced srclist._), and the directory's qeffile as the input script, it builds the construction in the current directory.

The qsg -f <file> option is usually used to run a script that is not contained in a script library, as in:

    % qsg -f file -- arguments
Typically, you run a script in this fashion until it is thoroughly debugged, at which time you place the script in a library.

The qsg -c <command> option is usually used directly from the command line, as in:

    % qsg -c hanoi 3 # run 3 ring tower of hanoi
For the --c option, the balance of the arguments are taken to be arguments to the script, thus the --- is not required.
qvrs variables used by qsg qsg scripts can access any qvrs variable or expression using the functions @(qvrs variable), @(qvrsexpr expression), or the short form of the qvrs function, @{variable}. However, four variables are used by qsg itself. These are:
QsgLibsnames of qsg script libraries to be automatically loaded.
QsgLibPathdirectory path to be searched for qsg libraries.
QsgMap[X]mapping for script X -- used to facilitate overriding the library version of X.
QefFilename of default script -- usually qeffile -- as found and set by qvrs.
Running a Library Script

To run a qsg library script, you simply need to know its name and the flags and arguments it accepts. The result of running a library script is almost always another script to another process. That is, scripts are both the input to and output from qsg. Running the qsg script to create a library or program, for example, does not directly create the library or program. Rather, it creates a mimk script to accomplish this. To actually create the program or library, you must interpret the generated script using the appropriate back-end (e.g. mimk). This processing, that is the invocation of qsg to create the script, and mimk to interpret it, is all managed by qef.

For a list of the scripts available in the qsg library, use the command:

    % x-qsg -L \*scripts

For a detailed description of any particular script, use the command:

    % x-qsg <scriptname>

9.4) Creating a Project Specific Qsg Library

The standard qsg library consists of seventy five scripts designed to handle the most common tasks involved in software production. We recommend that you do not modify any of these scripts, but we encourage you to examine them for useful constructs. To get the source for a specific library module, use:

    % qsgdump -S script

Some of the most important library scripts are described in Chapter 7.5: The Construction Script.

A project might need to extend the range of facilities offered by std.qsl to deal with languages and/or file types not currently handled. While you could add new scripts to the standard qsg library, we recommend that you create new a new project or organization specific qsg library instead. This is best done as follows:

  1. create a directory called qsglib (or qsl) in the top directory. This could be done within the project's tree or in a supplementary project created to hold organization specific QEF files -- see Chapter 12.11.
  2. create the required scripts in that directory with *.qsg suffixes. Avoid using any names already in use in std.qsl, other than qsl_init.qsg which is required in most qsg libraries. A qsl_init script might be required to map suffixes to processing scripts -- see qsl_init(x-qsg).
  3. create the following qeffile in the new directory:
        set Suffixes qsg
        Begin qsg -M -l-n
        mkqsglib -nname -v @argv
    Note:The --l-n suppresses the normal inclusion of @QsgLibs named libraries. The name should be a meaningful name that does not clash with any *.qsl file in <qtree-root>/lib/qsg. The --v, which causes a version string to be added to the library, is optional.
  4. Add the following line to the qeffile in the top directory, assuming that it is a qefdirs script:
        qsglib B
    The `B' specifies that the install operation is to be done if the Install or Local constructions are requested. The line must appear before any other directory that uses the new library.
  5. Add the following lines to the top level tree.vrs file:
        addpath QsgLibPath @_DestDir_/lib/qsg @ProdDir/lib/qsg
        append  QsgLibs  name
    If ProdDir is not been defined, elide the ProdDir directory. The name is the one used in step 3.
See Section 8: Script Generating Principles for guidelines on script generations.
Note:Some organizations create a site wide qsg library which is prepared as described above. Individual projects' tree.vrs or p_sysnm.vrs files are modified to add the required @QsgLibPath and @QsgLibs settings.

9.5) The Qsg Script Language

A qsg script has the following structure:

    summary <flag_spec> [-] <argument_spec>
    <explanatory text>
    endsummary

    # zero or more procs
    proc <name> <flags> [-] <arguments>
    ...
    endproc

    <script> 

Both the summary and the procedure definition(s) are optional. The summary defines the flags and their types accepted by the script. The summary/endsummary keywords can also bracket a text description, displayed by qsgdump -X. The proc keyword begins a procedure. Procedures are local to the defining script. The arguments specify the name of the procedure and the flags, if any. The procedure terminates with endproc. The [--] in the synopsis is literal (i.e., not an optional `--'). A `--' is used to terminate flags if the first argument begins with a `--'. See *defs-kws(x-qsg) for more information on the summary and proc keywords.

The actual script consists of keywords, variables, and arguments.

Variables are lists of words. A variable's value may be incorporated into an argument list by placing the @ character before it: @L is the value of the variable L. Literal spaces, tabs, and `@'s can be embedded in an argument list by preceding it with an `@'. The @ character can also be used to escape newlines to split long lines.

Any list can be modified by a post-fix ~ operator (e.g., ~x/sfxs/, which selects those members of the list with the suffix "sfxs".). The tilde operators may be compounded by concatenation, and are evaluated left to right, with each operator operating on the list created by the preceding operator. See Appendix F: QSG Listops.

9.6) Example Qsg Script

The following is a contrived qsg script that contains examples of some of the syntactic forms of the language, with comments to explain their use and semantics.
Note:`#' at the beginning of a line is a comment. `@#' in the middle of a line begins a comment. `@' at the end of a line specifies that the line that follows, minus leading spaces and tabs, is joined to the current line.
summary [-ab] [-p parm] [-l list]+ [-o[opt]] [-] @
	arguments ...
short optional description

-a		a boolean flag -- variable aFlag contains value
-b		another flag
-p parm		value assigned to pParm -- only one allowed
		second instance will raise fatal error
		This description should include the default.
-l list+	values assigned to lParm -- multiple instances
		allowed
-o[opt]		optional value -- oOpt~0 is zero if -o not
		specified, one if it is.  Optional value assigned
		to oOpt~1
args ...	strictly for documentation -- no interpretation
		all arguments after flags assigned to argv
		If first argument begins with `--' precede with `--'

This is a short description of the script.  When compiled, this
description can be extracted using qsgdump.  qsgdump can also
produce an x_db entry for inclusion in a x_db database.

The summary text is optional, but the flags list is required if
script has any flags.  The [-] is required.  The other `['s and
`]'s, other than those in -o[opt] are optional.
endsummary

# example proc
proc num [-rl] [-] ...
	# if ! -r return decimal form
	if ! @rFlag
		returnval @argv
	fi
	# @(libraries) yields list of loaded libraries
	# @List~=/str/ yields elements in List equal to str
	# @List~v yields 1 if List is empty
	if @(libraries)~=/dtree/~v  @# test if dtree lib loaded
		qsglib dtree  @# load dtree library
	fi
	# if -r return roman numeral; lower case if -l
	# @<roman ...> is call to library script roman
	# @(flags l) is call to built-in flags function which
	#  will yield -l if @lFlag != 0 (i.e., -l was specified)
	returnval @<roman @(flags l) @argv>
endproc

cset pParm default @# set pParm to default but only if
		# not already set.
>output this line and the number of arguments: @argv~l
<\1>Output argument list, splitting over multiple lines@
	if necessary with \ escaped newlines and 1 tab indent@
	for subsequent lines.  Arguments are: @argv

# output roman numerals for 1 to 20
set I 1
repeat
	>@I: @(num -rl @I)
until @[I @(expr @I + 1)] > 20
# @[I list] assigns list to I
# Note: @[/list] sets global variable named by first
#	element to the balance of the list
# @(expr ...) evaluates argument arithmetic expression

# output roman numerals for arbitrary list
for I in 4 49 94 56
	>@I: @<roman @I>
endfor

# can just name library script or proc as first keyword
hanoi 3  @# run towers of hanoi for three rings
# For hanoi source use: qsgdump -S hanoi
# For a similarly recursive merge sort see: qsgdump -S sort

# list files in current directory by suffix
set list @<readlist -p ls>      @# get list of files
for sfx in @(uniq @list~e)      @# for each unique suffix
	<1>@sfx:@	@list~x/@sfx/   @# list *.sfx files
endfor
if @[nosfx @list~!m/*.*/]~n
	<1>None:@       @nosfx  @# list files without a suffix
fi
Note:For discussion of use of ~ postfix operator see faq7(x-qmisc).

9.7) Qsg Variables

qsg variables come in three flavours: local, global, and first-time switches. Local and global variables are lists of white space separated elements. An `@' escaped space, tab, or `@' can be used to embed literal spaces, tabs, or `@'s in a list element, although they are converted to 037, 035, and 036 respectively. The encoded forms are converted to the normal form on output.

Local variable names are one of more alphanumerics or underbars, the first of which cannot be a digit (i.e., the same as C modulo the `$' allowed by some C compilers).

Global variable names can be any normal printable unsigned ASCII character greater than a space (i.e., bang to tilde), however use of `(' or `)' will make it awkward to retrieve the value using the literal name.

First time switch names can also be any sequence of printable characters excluding white space (one can use escaped spaces and tabs if really necessary).

The local variables are local to the current instance of the script or proc. When a script or proc is invoked, the flag processing then will set any specified flag's variable. The simple --X flag's variable (e.g., XFlag) is set to 0 or 1 depending on whether or not the flag was specified. The arguments to a parameter flag --P are assigned to PParm and OOpt is set to any optional parameter values. The argv variable (which is always defined) is set to the arguments of the call after the flags and options. All other local variables are set to the empty list.

Global variables are, obviously, global and are accessible to any script or proc, as are first time switches.
Note: Given the global nature of global variables and first time switches, the function @(scriptnum) is often used as part of such a variable's name when access to such a variable should be limited to the current script, its procs and possibly subsequent or recursive calls to the same script.

Global variables are set or modified using gset, gappend, gpop, and gprepend. The latter two functions are often used to implement stacks. In addition to the keywords, the special expansion @[/List], as in:

    ... @[/ Example example value]
sets the global variable named by first word of the List (e.g., Example) to the balance of the list (e.g., example value). A global variable's value may be retrieved using @(g name) or its alias @(global ...).

First-time-switches are used to prevent processes from being done a second time such as the processing for a source file or the output of the include of a header file. A first time switch can be set using the keyword set1st or the test and set function 1stset as in:

    if @(1stset switch-name)
	# switch-name was not previously set but it is now
	# ... first time only code
    else # 1st time switch was set previously
	# 2nd and subsequent time code
    fi
A first time switch can be tested without setting it using the function @(notset name) which returns 1 (0) if the 1st time switch name wasn't (was) previously set.

9.8) Script Generating Principles

Frequently, as discussed in Section 4, a project can benefit from having its own qsg scripts to supplement or override those provided by the standard qsg libraries as listed in Section 2. The creation and use of such a library is described in Section 4 and project.qsl(x-qmisc).

This section briefly discusses some of the principles that should be followed in developing new scripts that will conform to the normal style and form of the standard scripts.

qsg-scripts(x-qsg) This item lists the standard scripts. It should be reviewed as it is likely that there is an existing script that is similar to the script that you need to create.
qsl_init Your library should have a script called qsl_init. This script is invoked when your library is loaded. It is typically used to bind scripts to suffixes, initialize global variables such as the target keys, etc. To view the source for the standard library's qsl_init, use:
    % qsgdump -S qsl_init
Summaries All scripts should have complete summaries giving the synopsis, a short description, descriptions of all the flags (including their defaults if relevant), and supplementary notes. These summaries can be converted into an x_db database if desired, but in any case they can be retrieved using:
    % qsgdump -X script
Types of Scripts The qsg-scripts(x-qsg) item lists the standard scripts, partitioning them into construction, command, make object, and support scripts. When creating new scripts, attempts should be made to make those scripts resemble existing scripts in their interface and purpose. Scripts should use the support scripts as much as possible. The more important support scripts are described briefly below.
Conventions Command scripts should be designed to take multiple argument files and support much the same --cdLTv flags as the other command scripts -- see commands(x-qsg). Scripts should provide the appropriate target, item, and remove directives. All tools used within a script should be named using the "_T_" form, as in _T_cc. All constructions should have a _T_touch(tool) dependency where tool is the primary processor of the recipe. The recipes should include _F_tool and _F_tool[file] to support specification of universal and file specific flags within the qvrs files.
cmds_X Scripts called cmds_X are used to process command *.X files and files with suffixes mapped to it using qsgcmdproc(x-qsg). A prime example of such as script is cmds_xdb which should examined as a prototype. Such scripts should process all its argument files, creating recipes to build all intermediate and installed files and the appropriate target, item, and remove directives.
mkobj_X Scripts called mkobj_X are used to process *.X files and *.sfx files for which mkobj_sfx has been mapped to mkobj_X (usually in the qsl_init file) using qsg keyword mapscript or by setting @QsgMap[script] in a qvrs file.
Supporting QSG Library Scripts
The following scripts are provided by the standard library for use by other scripts.
mkobj This script is used to output commands to construct objects. It outputs the qef directives to create a File's object file (e.g., File.o), its assembler file (e.g., File.s), its cpp output (e.g., File.o).
generic This qsg script is used to output qef directives and recipes to build and optionally install a file with a specified recipe. This script is commonly used when the file's processing is non-standard. finstall is invoked to install the file if the --d flag is specified.
target target file description outputs the qef #target line:
    #target file description
but only if there has not been a previous output for the same target.
item item file1 file2 ... outputs the qef #item line:
    #item file1 file2 ...
but only if there has not been a previous output for the arguments. #target and #item lines are output by qef when the --Ptargets option is specified.
rmfiles This script outputs #rm{obj,inst,objpat,instpat} directives to remove the named or pattern matched files when one of the Remove* qef directives is specified.
putdeps & strdep These scripts are used to output dependencies. putdeps is for prerequisite files whereas strdep is for strings. A string dependency will be stored in the history file. If the string dependency's value is changed, the target will be deemed out-of-date. String dependencies are normally used to store values that are not part of the recipe but will be used by the recipe's processes (e.g., an environment variable).
Further Examples and User Contributed Scripts
The qsg libraries misc and dtree are a rich source of example scripts for a variety of languages. To get a list of the scripts for these libraries use:
    % x-qsg -L \*dtree_qsl \*misc_qsl
To retrieve the source for a specific script, use:
    % qsgdump -llib script

9.9) Qsg and this Guide

We should not leave this chapter without a brief discussion of the use of qsg to produce and manage this guide. qsg, despite being a fairly simple language, is exceedingly useful and no example is probably better than the role that qsg plays in producing a guide like this both in its web and printed forms.

This text is written in qsg using the html library, which will be replaceable by an XML library in the future. This permits the use of variables such as @QSG which has been set to "@<tool qsg>" and will be translated into:

    <a href="appendix-D.html#qsg"><i>qsg</i></a>
that is: qsg. Chapter, section, and labels headings appear as:
    chapter -inum @(flags pn) Title ... @# --p and --n flags
		# are previous and next links.  Note '@#' used to comment
		# in an argument list as '#' is treated literally.
    section title ...
    label title ...
The example commands such as:
    % qsg -c hanoi 3 # run 3 ring tower of hanoi
that appear some 350 times in this guide are encoded as "@<cmd command # comment>". A --t flag is used if the command is to be linked to an entry in Appendix D. The @<cmd ...> script takes care of outputting the <pre>, the links, the font changes, etc. The text is just entered using the <<...>> form as in:
    <<
    ...
    The text is just entered using the ...
    ><label Command In Middle of Output
    More text, some in @<b bold> ...
    ...
    >>
So much for the source. The qeffile contains in part:
    gset PageMap @(call readlist @(findfile page.map))
    if @(option PrintVersion)
	qsg2html @argv
    else
	qsg2html -d @{_DestDir_}/pages @argv
    fi
The page.map file contains the mapping of source file names (e.g., c080.qh) to section names (e.g., chapter-09.html). The qvrs option PrintVersion is used to suppress installation of the galley versions and suppress the links in the pages. The qsg2html script will generate mimk dependencies and recipes for each of the source files, such as:
    c080.html:P: _S_(c080.qh) _DestDir_/lib/qsg/guide.qsl \
		<qtree>/lib/qsg/html.qsl
	    qsg -lguide -o c080.html -c _S_(c080.qh) \
		-p chapter-08.html -n chapter-10.html
    
    #rmobj c080.html
The web versions are produced and installed employing the same mechanism in a sibling directory using a spliced source path. Note that Appendices E through G are generated by x_db databases queries processed by qsg to produce HTML representations and the embedded links.

Yet another qsg script is used to invoke netscape --remote commands to produce the PostScript versions of the pages. The PostScript files are then read by still another qsg script to modify the clipping box, insert page headers and footers that incorporate the section titles and page numbers and produce the page number mappings to be used in the table of contents and keyword index, also produced by qsg scripts.

Finally qsg scripts are used to create the installation packages and book production forms.

Hence a single qef command will install the web pages, produce the book form, create the distribution package, and do the Chapter 10: file system integrity check via the simple application of a few qsg scripts.

For your edification, the frequently referenced hanoi source is listed below for those who have not as yet installed the Q-Tree:

% qsgdump -S hanoi
summary [-] n [from to spare]
run the towers of hanoi for N rings

N		number of rings to be moved
from		name of origin tower
to		name of target tower
spare		name of spare tower

Well why not?  If names of towers not provided,
default names used.

This script is provided for illustration and testing.
endsummary

proc hanoi [-]
	if @argv~0
		nset n @argv~0 - 1
		hanoi @n @argv~1 @argv~3 @argv~2
		# retrieve, increment and reset global Move#, and
		#	output the ring move
		>@[/Move# @(expr @(g Move#)+1)]: move ring@
			@argv~0 from @argv~1 to @argv~2
		hanoi @n @argv~3 @argv~2 @argv~1
	fi
endproc

if @argv~v
	fatal @(script): ring count not specified
fi
if !@(check @argv~0)
	fatal @(script): @argv~0: @(chk_msg);@
		1st argument must be numeric
fi
if @[N @(chk_value)] < 0
	fatal Tell me my dear @{Logname}, just what does@
		a negative number of rings look like?
fi
drop1st argv
if @argv~v  @# if no arguments left
	set argv this@ one that@ one over@ there
elif @argv~l != 3
	fatal arg count - must be zero or three towers specified
fi
gset Move# 0	
hanoi @N @argv

qsg is a remarkably useful little tool and it is fun to use.


c080.qh - 9.5 - 04/01/20 QEF Home The Guide's Table of Contents Previous Chapter Top Of Page Next Chapter