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. |
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 @argvv return No arguments specified fi >Arguments: @argv ^D % qsg -f tmp No arguments specified % qsg -f tmp hi there Arguments: hi thereYou 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: BeginWhen 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.
|
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:
To get a listing of the scripts provided by a particular library use: % qsgdump -L -llib -l-NThe 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 scriptTo 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_dbTo 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:
|
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:
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 -- argumentsTypically, 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 hanoiFor 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:
|
||||||||
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> |
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:
|
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. |
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.
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 -- oOpt0 is zero if -o not specified, one if it is. Optional value assigned to oOpt1 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 # @Listv 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: @argvl <\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 @liste) @# for each unique suffix <1>@sfx:@ @listx/@sfx/ @# list *.sfx files endfor if @[nosfx @list!m/*.*/]n <1>None:@ @nosfx @# list files without a suffix fi
|
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.
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 fiA 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. |
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 descriptionbut 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_qslTo retrieve the source for a specific script, use: % qsgdump -llib script |
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 hanoithat 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 fiThe 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.htmlThe 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 @argv0 nset n @argv0 - 1 hanoi @n @argv1 @argv3 @argv2 # retrieve, increment and reset global Move#, and # output the ring move >@[/Move# @(expr @(g Move#)+1)]: move ring@ @argv0 from @argv1 to @argv2 hanoi @n @argv3 @argv2 @argv1 fi endproc if @argvv fatal @(script): ring count not specified fi if !@(check @argv0) fatal @(script): @argv0: @(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 @argvv @# if no arguments left set argv this@ one that@ one over@ there elif @argvl != 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 |