═══ 1. Introduction ═══ Introduction This is a generic preprocessor which allows you to use some very powerful features such as "#if", "#define" and "#include". The preprocessor is known to work under: 1. Windows NT/2000 2. Windows 95/98/ME 3. OS/2 4. UNIX (including Linux, FreeBSD, Solaris) 5. BeOS 6. Windows 3.1 (use DOS) 7. DOS PPWIZARD is more powerful than virtually any other preprocessor available and unlike many others remains simple to use (no complicated syntax); its replacement syntax is HTML like. PPWIZARD can be particularly useful for people who like to hand code their HTML and use an HTML editor. The use of a GUI-based editor does not, however, rule out PPWIZARD's use and some editors allow you to define your own tags (allowing you to add PPWIZARD's tags and commands). The free "Regina" interpreter is required for operating systems other than OS/2 (this is installed for you under Windows). Before I go further, if it all starts to sound complicated (and it certainly can be) then please check out the Beginners Guide section (you may wish to look at some of the sites PPWIZARD users have created at http://www.labyrinth.net.au/~dbareis/ppwusers.htm). Since PPWIZARD is a generic tool, using it can be as easy or as hard as your level of experience can handle. Even at its simplest level PPWIZARD can easily save you heaps of time, not only initially building a site, but in keeping it up to date and running (where you will find all the work actually is). This preprocessor is commonly used as an HTML preprocessor as well as a REXX preprocessor, however there is no reason why this one preprocessor can't handle almost any file you have around (example: you can change the preprocessor to use "!if" etc and leave "#if" commands alone if you wish). Most people would probably find the #include and #define commands the most useful, as they could be used to ensure that you need never specify something more than once. For example, you might refer to a specific link (or image) in tens of places in different HTML pages but you can define it in one place. When you need to change it you make the one change and regenerate the HTML. It's not just easier and fast, it eliminates mistakes. You could set up your source and have automatic checking of the existence of any resources on your web page (no incorrect links). The "#if" support is much more powerful than that of any other preprocessor due to the fact that what it executes is REXX code. What this means is that any REXX expression can be called, including your own REXX procedures. The "#evaluate" command allows you to parse files or do whatever you need to in order to obtain the text you wish to use in your HTML. You can use this program to produce different versions of your HTML pages for different locations. For example, for an offline copy you may not want to have links to internet sites or may want to have different links. The preprocessor could be used in conjunction with an HTML editor, however it is most useful for power users. This tool can be used to automatically calculate image widths and heights, file sizes, or file dates and times, and basically do all the drudge work (the stuff most likely to otherwise quickly become out of date). By default excess leading spaces are removed from the output file so that you can format the input as much as you like without impacting download speed. If you can't explain why an error message is being displayed or your code is not generated as you'd expect then I highly recommend you try the "/debug" command line switch. I'd also like the debug output if you report problems. If you have used a previous version of the preprocessor then I'd recommended you examine the change history section to determine what changes might affect you. Please see my web page at http://www.labyrinth.net.au/~dbareis/ppwizard.htm for the latest copy of this program or contact me (Dennis Bareis) via e-mail (dbareis@labyrinth.net.au). I value feedback from users. If the examples in this INF version of the documentation don't look correct (fonts overlap, etc.) then you have removed "Courier 8' font from your operating system. Please restore it... Note that I would have loved to have written this in Java, however as a compiled language it does not have an "interpret" instruction. Apparently something is being added to version 1.2 which might allow something similar; I'll have a look then. The "interpret" instruction is important as it allows the preprocessor to be extended as well as doing a lot of work I'd otherwise need to do myself (and I wouldn't do it as well). I will not be rewriting the preprocessor in Java (as it wouldn't be compatible with the REXX version), but with any luck I'd be able to write any similar future stuff in Java.... ═══ 1.1. Operating System Status ═══ Operating System Status This free html preprocessor runs natively under OS/2 or under the free Regina interpreter (available at "http://www.lightlink.com/hessling"). You may wish to have a look at a list of some of the operating systems PPWIZARD users use (http://www.labyrinth.net.au/~dbareis/ppwusers.htm). Note that I only expect the PPWIZARD program to work correctly on the native OS/2 or Regina REXX interpreters. Note that Regina looks in the directories mentioned in the "REGINA_MACROS" environment variable for REXX scripts if they are not in the current directory (it does not use the "PATH" environment variable). Unless "ppwizard.rex" is located in a path mentioned in "REGINA_MACROS" then a command such as "regina ppwizard tryme.it" will fail unless PPWIZARD is in the current directory. Of course it will also fail if "regina" is not in one of the directories mentioned in the "PATH" environment or in the current directory. Your Source I have made the preprocessor cross platform. This means that PPWIZARD will run across many platforms, but does not mean that your source will build correct output for multiple platforms. There are issues that you will need to take care of to ensure that your code is cross platform also (if you care)! As an example of a mistake you could easily have made, you could have used the OS/2 "filespec()" routine instead of the PPWIZARD "_filespec" call. The resulting output would function correctly only on the OS/2 platform. Status Under OS/2 Works like a champ! Regina - All Operating Systems Some things that are currently disabled are:  /FILTERINPUT  /FILTEROUTPUT  #MacroSpace Some other situations not fully supported yet:  No colors used by default (except under OS/2). You could try "/Color" but it may not work.  PPWIZARD is not expected to work under old versions of Regina. Use supported versions and none before version "0.08f". Status Under Windows XP I don't expect any issues. Status Under Windows NT/2000 No known issues. I now do all development and testing under Windows 2000. Example command when "W32SETUP" has been used to install PPWIZARD is: ppwizard tryme.it Status Under Windows ME No known issues. It has been tested. Works as per Windows 98. Status Under Windows 98 People are happily using it under Windows 98. Works as per Windows 95. I believe Windows 98 has the same 5 or 6 year old bug with its command processor as Windows 95 (see below). Status Under Windows 95 PPWIZARD under Windows 95 works exactly like the DOS version. It appears that a bug in Windows 95 (thanks Microsoft!) might prevent you getting the return code and so automatically determining if everything worked or not. Obviously games don't require return codes! As for all non-NT based Windows releases, you will have to preceed the PPWIZARD command with "regina". Example command command is: regina ppwizard tryme.it Status Under Windows 3.1 Use DOS version of Regina. Status Under DOS My own web site is reasonably complex and the DOS (DPMI) version has successfully compiled it. Had to increase DMPI memory to do my whole site in one hit (*.IT), if you have a similar problem just call PPWIZARD many times (maybe processing "A*.IT B*.IT ... K*.IT" in one go and the rest the next. You get the idea! An even simpler method would be to use dependancies (/DependsOn); this way if you run out of memory, you simply restart the build and it will pick up from where it left off. Status Under Unix All command line switches can be specified using '-' or '/'. I believe that PPWIZARD will run under all unix operating systems (although some may need some tweeking such as with SunOS). I either test under or have reason to believe that PPWIZARD works under: 1. Linux Known to work with RedHat:  5.1  5.2  6.2 Ultrasparc Linux (64-bit kernel) 2. FreeBSD 3. SunOS Tested on SunOS 5.8 (64 bit enabled) using GNU "find" version 4.1 (64 bit) in place of Sun's regular "find". If you do not wish to change the "find" command (which appears to be very non-standard) you could use a /Hook of "GetFileList". 4. TSO I am modified PPWIZARD for it to work on REXX370 on OS390/zOS (Unix environment - omvs?). It may or may not work (at least for routine things). Let me know if you try - PLEASE. I now think it probably won't - yet. You will need to obtain the Regina source code and compile it (there are now binaries in Red Hat package manager format). All my testing used the generated "REXX" program. The source can be obtained from my http://www.labyrinth.net.au/~dbareis/regina.htm. Note that temporary files are put into the directory identified by the "TMP" environment variable, you must have write access to this. If the environment variable does not exist then files are placed into the "/tmp" directory. If you have any problems (such as PPWIZARD not locating the input file) then you may need to use the /RedirMethod switch. You may need to use /Hook (for "GetFileList"); if you need to use this to get PPWIZARD going then let me know (I need "-debug" output) and I'll fix it. As with all operating systems, I am keen to fix any problems. Unix is a bigger unknown to me with all its different shells, etc. If you have a problem, please use the "-debug" command line switch and redirect the command's output, along with the name of the shell you are using and any other relevant details (all zipped please). I will typically have a fix for you in a few days and maybe a workaround even faster. Status Under BeOS Looks like Unix to PPWIZARD. No known issues. Status Under Amiga Not supported however as regina is available for this operating system I am waiting for someone to offer to perform testing for me etc. It is not expected to be difficult to ensure PPWIZARD works on the Amiga. Status Under Macintosh OS X Maybe... It sounds like the operating system is Unix based and Regina works on this operating system. Let me know if you try, if it doesn't work it shouldn't need nuch tweeking to get going. Status Under AIX May or may not work (probably does), regina is available. Anyone using it on AIX? Status Under HP-UX May or may not work (probably does), regina is available. Anyone using it on HP-UX? Status Under QNX May or may not work, regina is available. Anyone using it on QNX? Other Operating Systems If Regina works on your operating system, but your operating system is not listed above, then contact me. If you are prepared to help (test changes, etc.), then I will try to get it to work for you. Before contacting me please download the latest "rexx4ppw" package from http://www.labyrinth.net.au/~dbareis/ppwizard.htm and send me the redirected output. Problems When reporting problems please run the preprocessor with the "/debug" flag and give the the command line used, the redirected output, and the source file(s). ═══ 1.2. Change History ═══ Change History Please note that my version numbers are of the format "YY.DDD" where "YY" represents the year and "DDD" is the day of the year (1-366). While this format does not let you know of the magnitude of any changes (my change history shows this) it does make it simple to know the "age" of a release.

Please let me know of any bugs or issues and do not assume that someone else has reported it. I have fixed all known bugs/issues. The very fact that you are having a problem means that I probably do not know of it! In rare cases I do get snowed under and forget things, in this case remind me! 1. Version "Next Release"  You tell me, feedback please! Have you ever looked at a product and said "Wouldn't it be nice if ...", well get on your backside and send an email, make it so! I'm not always right and believe it or not I don't mind being told so.  Your idea here :-). 2. Version 01.320  Fix to base directory validation problem in 01.316 when filemask began with '+'.  New "/COPY" switch (binary copy).  All processing mode switches (/COPY, /HTML, /OTHER and /REXX) as well as /DependsOn and /OUTPUT can now be specified per input mask. Extra code ensures backwards compatability.  The /Making switch is completely different. Default text now uses long output name and includes processing mode. 3. Version 01.316  The 'for' and 'set' "loops" would always go though at least once. Also improved "empty" set handling.  Output files created last run are now deleted by default on following build. New /DeletePrev switch to change this.  New /BaseDir switch (or "{ENDBASE}" filemask text) to allow you to process subtree easier. New "" definition to allow you to access the information. Removed limitation which restricted use of "{$path}" specs (its up to you to only use where appropriate).  New /OutHeader switch. This can add/alter or remove headers into output files.  Output Headers are now generated for files generated with the #output command (also see "NoHeader" parameter).  A default output header is now added to any file with extension ".VBS" (assumed to be VbScript).  Improved error reporting where "rexxsql.dll" can't be loaded (on regina versions which don't crash...). 4. Version 01.309  The _SysFileTree() routine was not working under native OS/2 rexxes. This would have prevented a few add-ons from working ("FTPLIKE" and anything relying on it).  Macros in any parameters passed on the " #{" command are now replaced. Syntax tweeked to allow you to access the internal loop counter which exists anyway.  More internal redesign to simplify porting. 5. Version 01.302  Made a lot of internal changes to try to port to REXX370 on IBM OS390 unix environment (omvs?), this has modified a fair bit of code for all operating systems. PLEASE let me know of any issues.  The #{ command has been extended to support "set" loops. This can also be used to bypass the commands nesting issue as it can effectively provide you with a "flat" nested (to any level) loop.  New ArraySplit(), ArrayRemoveDup() and ArrayTranslate() routines.  Windows install changes: - In non-english countries the start menu items were incorrectly going into the "programs" folder (should have gone into "Programme" for German etc). - New version of regina (2.2) now in Windows package.  Looks like I've been using the 2.2 beta as PPWIZARD would fail on some operating systems with the recently downloaded GA regina version 2.2 (the uname() BIF changed between the beta I was using and the official release - what is worse is that I requested the change!). I have corrected this problem.  New definition of "", this holds the "real" operating system for example if the "" symbol contains "UNIX", then this symbol might contain "FREEBSD" or "TSO". PPWIZARD now uses this value internally in most places.  Updated /#Include handling so that can be used in included files.  The #{ 'FOR' command has been improved to handle rexx variables that start with "_" or other valid non alpha characters.  Modified #import so as not to generate blank lines where you might have been trying to restrict the generated output.  Better formatting of any trapping rexx being evaluated in console or error file output.  Default quote debug characters now set to some quite "safe" non-blank characters.  You may need to modify your source, see following issues: a. While unlikely you might need to modify any existing use of "". It will no longer contain "WIN95 - WINXP" but only "WIN32" (for all). To get the specific operating system information you will need to use "". 6. Version 01.281  Windows install changes: - For install on Windows NT/2000, PATHEXT updating is now done last, if this fails all other setup has still been done. I will come up with something better in future. Anyone know of any reliable way of doing so (maybe utility)? - For install on Windows 95/98/ME, made "PATH" updating smarter so it won't update variables like "INFOPATH". - For install on Windows 95/98/ME, added work around for "Failed making backup copy" problem. It appears that WinME at unknown times can set the hidden attribute on autoexec.bat. We now remove any hidden or read-only attributes and use the "type" command in place of "copy". 7. Version 01.269  The installer for Windows now defaults the install directory for PPWIZARD to "C:\PPW" for DOS versions (Windows 95/98/ME). Other changes (to registry) to decrease the length of the command line allowing you to use longer filenames. Note Windows NT/2000/XP etc have no restrictions on file size. If upgrading you may wish to remove "C:\Program Files\PPWIZARD" from the PATH environment variable in "\AUTOEXEC.BAT".  Minor change to the MakeWebLinks() routine to add "-" (minus) to characters that are valid in a URL.  Documented existing GetQuotedText() and GetQuotedRest() routines. 8. Version 01.247  The #( command can now be nested.  Minor fix to improve error message if the file specified on a /Template switch does not exist.  Fixed another minor error reporting bug which occurred if ppwizard initialization failed very early. 9. Version 01.213  Fixed "T2H" and "WRAP" bug in #import ("DOPASS2" undefined). 10. Version 01.211  Created new StackPush() and StackPop() routines which can be used to store information or for validation where steps must be executed in pairs.  New "#PUSH and #POP stack commands to allow easier saving of macros and rexx variables.  The above mentioned stack changes have pretty much obsoleted the "PUSHPOPM.H" and "NESTCHK.H" add-ons. The functionality was moved into PPWIZARD to improve the performance of my BOOKMARK/FTPLIKE add-ons and PPWIZARD has some similar validation code internally which I will eventually update to use the new code. 11. Version 01.204  The #{ command has been extended to support simple "for" loops.  A new "*PpwPgm" dependancy type. This is used to replace the old method of depending on the version of ppwizard being used as this did not cover all possibilities.  A new "*Rexx" dependancy type which can execute rexx expression(s).  Added/reorganised some debug code. Fixed undocumented "DEBUG" command. 12. Version 01.197  Fixed a recently introduced bug which affected users using the OS/2 object rexx interpreter (incorrectly formatted call to "value").  Removed some caching of file timestamps, this removes a minor glitch which occured where a file is read if it exists and created if not.  Updated masks that GenerateFileName() can handle and all switches etc that rely on it.  A new "*CmdLine" dependancy type. This check is performed when /DependsOnComplete is ON (the default). 13. Version 01.187  Updated '{$?}' to correctly quote strings that contain both single and double quotes. 14. Version 01.183  New Dependancies filter capability if a rexx macro called HOOK_DEPENDSON exists. 15. Version 01.152  Fixed bug in Multi line import record filter where a EOF "command" to ignore the rest of the database was being ignored. 16. Version 01.135  The "*expires" dependancy cmd has been much improved.  New TimeStamp() routine.  Improved PPWIZARD Command line so that you can now use a number of characters to quote filenames or switches that may contain spaces (not just double quotes which for example don't always work under Windows/Regina).  Oops, accidentally disabled custom installs under Windows.  The "right click" build options would fail in Windows NT/2000 if the directory or filename contained spaces (this was not an issue under Windows 95/98/ME). 17. Version 01.129  A new dependancy type of "TODAY" added to "#DependsOn" command.  The #{ command would fail if used within a macro which expanded during #OnExit processing (could not locate end of loop). 18. Version 01.120  Fixed call to "OptionSetValue" around line 9930 which would fail under OS/2 using OREXX. 19. Version 01.112  Major improvement to "#OnExit" command.  Windows Install updated. 20. Version 01.102  New /UNC switch which turns off path slash reduction to allow UNC names etc.  Some #( related improvements.  Improved GetAmPmTime() and GetAmPmTimeFromHhMmSs() routines.  You can now specify multiple lines of output on the #error command.  Removed most of the "PPWIZARD Extensions" section, I will probably eliminate it altogether soon. 21. Version 01.091  New #( & #) commands. These are replacements for #OneLine & #OneLineEnd (although these will continue to exist - at least for a while).  New MakeWebLinks() routine to simplify processing of http & ftp addresses.  New QueryExists() routine to simplify checking file existence (getting full path).  Default of previous error file being deleted was not working correctly.  Minor change to UrlEncode(). 22. Version 01.083  New $$RXEXEC "$$" macro command which allows rexx code to be directly executed without requiring the usual annoying "linking" #evaluate command.  New BD2DATE() routine and the BaseDate() routine was rewritten (no bug just better code).  New AddTempFileToDependancyList() routine which allows you to indicate temporary files which should be ignored by PPWIZARD. The #DependsOn command also updated.  New ""  In "quiet" mode PPWIZARD no longer displays overall summary when no files were made.  You may need to modify your source, see following issues: a. The change above for the $$RXEXEC command required me to alter how "$$" macro commands are handled. The exact mechanism was not documented before so if you were relying on the action taking place BEFORE parameter subtitution then you should note that it now occurs AFTER! It is probably more "right" now. If you think it might be wise to allow for both let me know. 23. Version 01.072  New "GetDependancyInfo()" routine allows you to access input and output file dependancy information.  "#NextId" command tweeked so that value is only incremented if it was actually used.  New /Making switch.  You can now comment out items on the command line to aid in testing.  Minor change to fix ppwizard name in Copyright banner on non OS/2 systems. 24. Version 01.059  Fixed a bug preventing ppwizard running on OS/2 (native rexx). OS/2 problem probably introduced in the 01.036 version. Root cause probably earlier, self corrected but code now modified so can't happen again.  Changed "$trace" code generation so that it should now never produce invalid rexx or ppwizard code. This mainly affects blocks of rexx code that also expanded other macros or complex parameters. 25. Version 01.049  By default PPWIZARD now deletes generated files if an error occurs. You can control this via the new /DeleteOnError switch.  Command line switches can now start with either '-' or '/' in all operating systems.  When '-' used on /DependsOn switch, the copyright will not display unless there is work to do (ie ppwizard is quiet).  New option to not strip leading spaces from the value in a Multi Line import.  Added option which allows you to disable PASS2 processing on #import. 26. Version 01.036  Fixed bug in "_SysFileDelete()", it would not correctly delete a file containing spaces in all operating systems except OS/2. This would sometimes have prevented an output file being built where the directory or file components contained spaces.  New "MustDeleteFile()" routine.  New "#option" of ParmVal.  New "OptionGet()" and "OptionSet()" routines. 27. Version 01.029  Fixed up glitch with OS/2 install batch file.  Updated doco for #import SQL to show how you can access Excel Spreadsheets and text based databases such as command seperated value files.  Added an example of how bar or pie charts can be automatically created under Windows and saved as "GIF" or "JPG".  You may need to modify your source, see following issues: a. The "Die When Unused Parms" validation had a minor bug and has now been enhanced, a number is no longer accepted. 28. Version 01.022  The "expand all macro parameters as rexx code" would fail under regina if a parameter had a very long value.  New SStrip() routine.  New Add2() routine.  New LoadRexxSql() routine.  New "ID3.H" addon which can read ID3 version 1 and 1.1 tags (typically used on MP3 files for song title etc).  Fixed up a few "case" related issues with Unix, not in ppwizard itself but in "tryme.it" etc.  Added example of automatically reading EXCEL spreadsheet via VbScript.  Minor change to "" code, not backwards compatible however extremely unlikely to affect anyone. 29. 01.013  While you could always perform SQL imports directly with rexx code, I have now simplified the process by updating the #import command making it very simple to perform imports of SQL data from MS Access etc. Other minor import tweeks.  New ErrorSQL() routine to dump information on SQL errors.  New SetXCode() routine makes it easier to make a large number of definitions. 30. 01.007  New "Die When Unused Parms" macro validation.  The "Expand All Unused Parameters" tag no longer marks parameters as being used. Also note there is now also a tag which will reset "used" state.  Fixed and enhanced "expand all macro parameters as rexx code".  More tweeking of Windows install package. The "PPWW32.ZIP" download now simply wraps the "EXE", the ZIP file exists only to cater for the many sites that point to it. There is now a simple debug option as well as a "no setup" option. 31. 01.002  Added a Wise Installer OLE automation example which allows you to generate MSI (Windows Installer) packages via a simple "user friendly" script. VbScript (no knowledge of this language is required) is generated which is then executed from the command line or make files to generate the MSI (and WSI) files.  Fixed bug in /ConsoleFile switch and improved logic a bit.  Changed FindFileInPath() routine to allow you to specify directory trees to be searched.  The "FILEINFO.H" header was changed so that not only can you specify a path but you can also specify a search path (as per FindFileInPath()). This should not effect any existing use of the header.  Changed the FindFile() routine to always search relative to current directory first (while slightly less flexible, this makes it more efficient).  New "expand all macro parameters as rexx code" facility.  New "Expand Macro Name" facility.  Changed GetEnv() routine to log use when debug is on. This makes it easier to understand ppwizard's use of environment variables as well as your own.  Fixed minor bug in handling of "$$" macro commands.  Added "rexx stem" like example to "Macros With Optional Parameters".  Better trap output is written to console/error files.  More tweeking of Windows install package. Older Entries Than Those Above If you need to see older entries then please have a look at my html documentation as I had to remove this information from the IPF/INF version due to compiler problems. ═══ 1.3. Installing PPWIZARD ═══ Installing PPWIZARD Please see one or more of the following sections: 1. Hand Installation 2. Window's Install 3. OS/2 Install ═══ 1.3.1. Hand Installation ═══ Do I need to hand install at All? There are some special setup programs or information available for these operating systems:  OS/2  Windows 95/98/ME/NT/2000 If your operating system is listed above please read the appropriate section before proceeding. If it is not listed, any information you can provide will help write a new section for your operating system for others. Looks like I need to hand install! This section describes how to install PPWIZARD so it can be used from a command line or batch file. Windows and OS/2 setup programs do extra work to set up PPWIZARD so that they can be used via their graphical shells (Windows Explorer and OS/2 WPS); this sort of setup would be perfectly possible in any operating system and while only a minor tweek to what is done for OS/2 or Windows is not described here (maybe in the future - any help appreciated...). Note: to simplify installation and testing I suggest that Regina and PPWIZARD be installed into the same directory. The information shown here can be applied to any operating system supported by PPWIZARD. There is one and only one PPWIZARD runtime (distributed as "PPWIZARD.REX"), this runs on all operating systems. PPWIZARD detects the operating environment (REXX interpreter and operating system) and executes accordingly. REXX Interpreter PPWIZARD requires a REXX interpreter, only the following are supported:  Native OS/2 interpreters Of course no installation required for these!  Regina This is a free product which you will need to obtain. Download this from http://www.lightlink.com/hessling/. Note that if you already use a different REXX interpreter then Regina should be able to run alongside it, as it has few requirements. For ease of use Regina should be installed in a directory that is in your path as this means that you will not have to enter the full name of the program but can just enter "regina". The directory containing PPWIZARD should also be in the path as well as the Regina environment variable REGINA_MACROS. Note that if Regina can't find PPWIZARD, it comes up with a message similar to: Error 3 running "ppwizard.rex": Failure during initialization Error 3.1: Failure during initialization: Program is unreadable If you see this message, PPWIZARD is not corrupt, it simply can't be located. Double check that the directory containing PPWIZARD is mentioned in Regina's REGINA_MACROS environment variable. PPWIZARD  The directory containing PPWIZARD should be specified in the path.  Under OS/2, PPWIZARD has the extension ".CMD" and not the ".REX" that is used in all other operating systems. TESTING PPWIZARD PPWIZARD should display an error message (no files specified) if one of the following commands is used:  PPWIZARD This form should work in OS/2 as well as Windows NT and 2000. This is because these operating systems either know about how to execute REXX code or can be told. Please tell me if you know how to configure other operating system to work this way.  REGINA PPWIZARD This form will be required in Windows 95/98/ME and DOS. Unix, BEOS, etc. probably also require this form. If neither of the above two commands work, then the chances are you have made a mistake in configuration or you haven't rebooted since your last change. If it still fails after a reboot, change to the directory where you installed Regina and PPWIZARD and try again. If you can't work it out then contact me (dbareis@labyrinth.net.au) for help. If one of the above works then please see the PPWIZARD command line section of the documentation for more information on how to run it. ═══ 1.3.2. Window's PPWW32.EXE ═══ Installing using PPWW32.EXE in Windows

The "PPWW32.EXE" download for windows is a self extracting version which means that no separate unarchiving tool is required. This contains the Regina interpreter, PPWIZARD, and documentation in HTML format. Nothing prevents you hand installing PPWIZARD on Windows, however this download makes the installation much easier and sets up the Windows shell so you can work via Explorer if you wish. If you do hand install, then I assume my Windows install is doing something you don't like; let me know and I will probably do something about it. Note that the install process does not delete any files in the install directory if it exists. If you wish, you could delete this first, however if you have installed files from other downloads into this directory do not do this! PPWIZARD has uninstall support. Simply uninstall it as you would any other application. The install procedure is as follow: 1. Windows 95 users might need to download http://www.labyrinth.net.au/~dbareis/zip3rdp/msvcrt.exe. This is a self-extracting program which contains the Microsoft 'C' runtime (must be installed into the c:\windows\system directory). Check if it is already in your directory, if not then run this program to install. 2. If you have the EXE simply execute it to unzip the contents and run the installation. I recommend that you install into the default location of "C:\Program Files\PPWIZARD". 3. If you have the ZIP you need to unzip it with WinZip or similar tools and then run "SETUP.EXE" (a renamed PPWW32.EXE) to start the setup. 4. Follow bouncing ball. PPWIZARD creates a sample HTML page which it displays as part of the setup. 5. The install directory is added to the PATH and right click options appear in Explorer on "standard" extensions (see "PPW_95.RIT" or "PPW_NT.RIT", depending on which platform you are on, for details on these and other associations). 6. Reboot before using. 7. If you right click on ".IT", ".X" or ".PPW" file types the PPWIZARD build options should appear and work! Shell Integration (Explorer context menus) This doco needs more work, however if you right click on ".IT", ".IH", ".X", ".XH" or ".PPW" files you will see edit and build options that PPWIZARD has installed. ═══ 1.3.3. OS/2's OS2SETUP.CMD ═══ Setup PPWIZARD for OS/2 WPS Run "OS2SETUP.CMD" to install PPWIZARD for a graphical environment. This creates a PPWIZARD folder on the desktop with some doco icons plus an "association" folder. I have left the association folder visible so you can see the icons along with their associations. Do not delete these! Setup PPWIZARD for Command Prompt or Batch Unless you wish to specify the full path to Regina and PPWIZARD you will have to update CONFIG.SYS for the "PATH" and "REGINA_MACROS" sections (see Hand Installation). ═══ 1.4. FAQ ═══ PPWIZARD FAQ The following (currently short list) of questions are answered: 1. Can ppwizard accept options from a configuration file? Currently I have some very long command lines and it's hard to swap between frequently used configurations. 2. I have a perfectly working series of lines that I wish to place into a macro. The macro takes one or more parameters so that I can generate many versions of the output. I use the example tags, #AsIs" or #AutoTag" commands but these don't seem to be working correctly. What am I doing wrong? ═══ 1.4.1. QUESTION #1 - Does PPWIZARD support config files? ═══ QUESTION #1 Can ppwizard accept options from a configuration file? Currently I have some very long command lines and it's hard to swap between frequently used configurations. ANSWER You can use the /List switch to load files containing command line switches. This method allows you to comment switches. You can include other list files however no checking for infinite loops is performed. PPWIZARD can also accept switches from environment variables. In most operating systems you can either put your options in "config.sys" or in a batch file (such as "autoexec.bat") that you run for your project. You can create a whole range of different common options and select from them as you wish, hopefully the following example demonstates the method: @echo off REM *** YOU MIGHT WISH TO SET THIS IN "AUTOEXEC.BAT" ETC ******* SET PPWIZARD_OPTIONS=/beep /color:n REM *** NOW SET SOME OTHER STUFF **** SET PPWDEBUG=/debug /option:DebugLevel{x3D}"-ALL" SET STUPID=/DependsOn:out\*.DEP SET OTHERS=/GetEnv:Stupid REM *** START PPWIZARD *** if "%1" == "" ppwizard *.IT /GetEnv:OTHERS if not "%1" == "" ppwizard %1.IT /GetEnv:OTHERS REM *** IF I'd wanted debug *** goto Endbatch if "%1" == "" ppwizard *.IT /GetEnv:PPWDEBUG /GetEnv:OTHERS if not "%1" == "" ppwizard %1.IT /GetEnv:PPWDEBUG /GetEnv:OTHERS :Endbatch ═══ 1.4.2. QUESTION #2 - My macros are not generating output correctly? ═══ QUESTION #2 I have a perfectly working series of lines that I wish to place into a macro. The macro takes one or more parameters so that I can generate many versions of the output. I use the example tags, #AsIs" or #AutoTag" commands but these don't seem to be working correctly. What am I doing wrong? ANSWER The #AsIs and #AutoTag commands only work on data read directly from the a file. This means that you may need to use a bit of trial and error (maybe swearing a bit) and you can get it to work. What is probably easier is rather than creating a macro, put the information into its own header file, then instead of macro parameters you simply #define+ each "parameter" prior to each #include command. ═══ 1.5. Bugs, Problems or Suggestions ═══ Before asking questions, I would appreciate it if you'd ensure that your answer was not in the FAQ or this manual! Requested Information - Bugs or Problems If reporting bugs/problems please supply: 1. A detailed description of the problem. Please don't bother wasting your and my time by telling me "it did not work". 2. All files involved (input, output, and any batch files used to run the preprocessor). You have hopefully trimmed out everything which is not required by me to recreate the problem. 3. When supplying the redirected output from PPWIZARD please ensure that you had used /DEBUG on the command line to turn on debug mode. The easier you make it for me the faster I will be able to come up with a fix or tell you what you're doing wrong, etc. Reporting Bugs/Problems or Suggestions There are two main ways to report PPWIZARD issues or ask questions. They are: 1. PPWIZARD Discussion List People who are very interested in PPWIZARD can now join an e-mail based discussion group, any e-mail sent to ppwizard@egroups.com will be seen by all subscribers. Hopefully I won't have to answer them all, but if one person answers, everyone gets the benefit of the response. All messages are archived so you can always go back and see previous messages. I will also make announcements on this list. If you think the problem might be a PPWIZARD or Regina bug (which you think others probably haven't encountered) you may wish to contact me directly as others may not be interested (we don't want too many messages). Please don't attach large files to e-mails sent to this address (there is a 100K limit as well anyway). We'll have to see how it goes. Hopefully it does not need to become moderated (I probably haven't got time for that!). 2. Authors Email Address I will take feedback in this manner but in general prefer the e-mail list mentioned above. Exceptions might be where you have large attachments, you don't think anyone else would be interested, you don't want to join the group (why not?) or you really want to hammer me! If you must e-mail me directly then send it to dbareis@labyrinth.net.au. If I think it's appropriate I will "CC" the above discussion group with my response. If you do email me directly please make sure your reply address is valid! I have spent quite a bit of time on a number of replies that were rejected (either unauthorised or no such email address). I respond to all emails that require one, if you don't get a reponse reasonably quickly then I didn't get your email, the response got lost somehow or I'm on holidays! Please zip attachments. This reduces the size of the e-mail and ensures that the information gets here uncorrupted. Known Bugs or Problems The following bugs are PPWIZARD bugs: 1. None Known. The following bugs may occur when using the native interpreters under OS/2: 1. None Known. The following bugs may occur under any operating system using Regina (I will assume on "one of my recommended versions only"): 1. The debug time will be plus or minus a second (this can produce negative times, etc.). 2. Regina has a number of 'query exists' bugs, the one that might affect you is if you specify an input file such as "C:\CONFIG.SYS" and PPWIZARD tells you it can't open the "CONFIG.SYS" file in a completely different directory! Another one is where "garbage" might appear after a filename. ═══ 1.6. Disclaimer ═══ Disclaimer I believe it is very unlikely that PPWIZARD or Regina will cause damage to your system, however I feel that it is wise to advise you of steps you can take if your data is highly critical. I wish to stress that you take full responsibility for ensuring that PPWIZARD (or any other software related to PPWIZARD) is suitable for use in your intended environment. PPWIZARD is supplied "as is" and may contain bugs. It is just impossible to test software (or even information) in all environments as there are just too many possibilities. For this reason you should test any software/information yourself for suitability before using in production or placing onto machines containing important information. By doing this you will have helped ensure that there are no unintended drastic side effects. Prior to testing it is recommended that a full backup of your hard disk be performed. Updating from Older Versions While I will try to keep PPWIZARD backwards compatible with older versions, I will at times (intentionally or not) change it in such a way as to require you to make changes to your source (batch files, code, etc.) if you wish to upgrade to the newer version of PPWIZARD. I will have expected you to have read the Change History as it will usually indicate any source changes that you might need to make, plus any other potentially important information. It is recommended that you backup your source (including any batch files, etc.) AND the older versions of my programs before trying a newer version. LINKS Any links I mention are provided "as is"; it is up to you to determine the quality of any site I link to or any software I mention... ═══ 2. Beginners Guide ═══ Beginners Guide This page will attempt to show you, in one spot, all the basic information you will need to know. I will refer to HTML generation here, however almost everything said will also apply to other types of generation (such as REXX code). Because this is a beginners section some of my statements will be greatly simplified and therefore may not be strictly correct. PPWIZARD is a free tool. Its basic aim is to allow a template or style-sheet design approach to web sites. It can aid in ensuring that the look and feel is the same across all your pages and can automate many common and difficult tasks. This manual was written using PPWIZARD. PPWIZARD is an extremely powerful and capable tool and this appears to make some people believe that it is complex to use, this I believe to be wrong. Just because a feature exists does not mean you have to use it. To use the basic features as described below is not difficult and I would say that ppwizard does it in a simpler and more straight forward manner than any other preprocessor available. Most other preprocessors are flawed by design and are typically also too simplistic. You have nothing to advance to once you have learnt the fundamentals and by the time you realise you are being limited by the preprocessor's basic capabilities you are committed to using it. One of PPWIZARD's main aims is to ensure that you only need to do (specify) something once, no matter how many places require it. Because of this, testing becomes easier, bugs are found faster, and your site becomes more reliable. As a further aid you can use my free URL checker to check that external links all exist (detect 404's before your users do)! PPWIZARD does not "clash" with normal html syntax, for this reason you should be able to take any existing html pages and slowly modify them to use more and more ppwizard features. If you have any problems getting started with PPWIZARD or understanding things, then please email me at (dbareis@labyrinth.net.au). I do not mind questions of any sort as long as some effort at reading and understanding the documentation, etc. has been made! It is also best to supply any sample code that you have been trying, so I can see where you are going wrong. So...let's begin... There are really only two easy commands that you will need to start with. They are: 1. #include This command allows you to include another file. There are no restrictions on where this file is location or it's name. 2. #define This command allows you to define something like an e-mail or web address in one place and use it in all your pages. The "#include" Command This command allows you to include one file at any point within another file. The included file can contain commonly used text, consisting of one or more HTML paragraphs, an HTML header or footer, or macros which create text output. Since the included text exists in only one place, all that is required to make a change is to edit one file and then regenerate the HTML (see below). The "#define" Command This command allows you to define common components such as e-mail and web addresses in one place. Here are some examples: #define MyEmailAddress dbareis@labyrinth.net.au #define ImgUpdated updated #define ImgNew new #define HttpMainJavasoftPage java.sun.com #define HttpJavaFoundationClassesPage <$HttpMainJavasoftPage>/products/jfc/ In the above commands you will notice how we give "names" to common components, for example I called my e-mail address "MyEmailAddress" and gave it the value "dbareis@labyrinth.net.au". You will normally put all of the commands like those above into a single file; let's get creative and call it "common.ih" (you could call it absolutely anything). Now, in any HTML page that requires one of the above definitions, you would place a statement similar to the following, near the top: #include "common.ih" Using Common "#define" Components To refer to a previously defined value you preceed the "name" you gave it with "<$" and end it with ">". For example, the following text refers to the e-mail address we defined above:

If you have any questions or suggestions for improvements please feel free to e-mail me. You might have previously noticed that I snuck in a #define that also referred to a previously defined value; it was this command: #define HttpJavaFoundationClassesPage <$HttpMainJavasoftPage>/products/jfc/ Quotes in PPWIZARD PPWIZARD's quotes are similar to HTML's in that both single and double quotes can be used; where they differ is that virtually any convenient character can be used. The following are all valid quoted values:  "quoted value containing the ' character"  'quoted value containing the " character'  +quoted value containing the " and ' characters+  $quoted value containing the " and ' and + characters$ Generating Your HTML The main concept to understand is that what you edit is called source code and what you create from this source (with PPWIZARD) is HTML or output code. You would never edit the generated HTML; you go back to the source, make whatever changes you require, and then regenerate new HTML. I recommend that your source files use the extension ".it", except for any source files that are common and are only included by other source files (for those, use the extension ".ih"; these types of files are frequently called header files). Generation via Windows Explorer or OS/2 WPS Any operating system that supports icons can be configured to run ppwizard so that you need never use a command line. The Windows and OS/2 install packages both perform setup for this purpose. In Windows and OS/2 this allows you to right click on an ".IT" file and select "Generate HTML" off the context menus (OS/2 users will find the option under the "Open" menu). There are other menu options such as for editing the file. PPWIZARD has also set up the GUI environment for project files so right clicking on these files brings up edit and build options. Generation via a Command Line If you follow the naming conventions mentioned above then you can simply recreate all your HTML with the following command: ppwizard *.it The above command should work on OS/2 and should also work on Windows NT and Windows 2000, other operating systems require the free "Regina" interpreter (see http://www.labyrinth.net.au/~dbareis/regina.htm) and can't be configured to run it automatically. Regina is very easy to install and the executable will be called either "regina.exe" or "rexx.exe" (no extension under unix). Thus if the the above command does not work try: regina ppwizard.rex *.it OR: rexx ppwizard.rex *.it If none of the above work then you should check out the "Hand Installation" section for clues. Getting slightly more advanced, you may get sick of rebuilding all your HTML when only a page or two needs to be processed; this command will only regenerate those that require it: regina ppwizard.rex *.it /DependsOn:*.dep Getting even more advanced, I like to keep source files in one directory and generated files elsewhere. The default HTML extension is ".htm"; this example also shows how this can be changed: regina ppwizard.rex *.it /DependsOn:out\depend\*.dep /Output:out\*.html Tab Characters In Source By default PPWIZARD generates warnings when it encounters tab characters as it really can't correctly process these without your help. By default it also converts each tab to a space. If you do not wish the warnings (which will also by default prevent dependancychecking from working) then the easiest solution is probably to configure your editor so that it generates spaces when the tab key is used. If that is not an acceptable solution to you then you should use the /option switch or the #option command to configure the Tabs setting, for example: regina ppwizard.rex *.it /option:Tabs=ToSpaces Capturing PPWIZARD's Output You should investigate the /ConsoleFile and /ErrorFile switches as these can capture almost all output. Not all debugging output can be captured however so at times you will need to redirect output from the command line. Please be aware that due to Windows NT/2000 bugs even if PPWIZARD is configured such that you don't normally need to specify the rexx interpreter on every PPWIZARD command line you will need to when redirecting, an example under windows follows (note that almost all operating systems use a very similar syntax): regina ppwizard.rex *.it /debug > c:\tmp\output.txt 2>&1 Organising Source Destination Trees You might already have a directory tree which is an image of your web site (contains images and html etc). This is useful for local testing and simplifies things when updating your web server. you will pass through PPWIZARD). Now you can use ppwizard to "make" the images (copys you don't forget which is which!). Note that if you wish to use graphical HTML editors you should have a look at the "/HideCmd" switch. The use of separate tree, the "/COPY" switch and "/HideCmd" would be a good approach if you wish non-technical people to maintain the source (or maybe while you get used to PPWIZARD and test it out). tories and deleting obsolete files or directories. If you use WINDOWS I have a free self installing download that makes it extremely easy to setup (unlike the official download...). What Next? You will want to read up more about macros and macro parameters. These (if you are careful) will allow you to create CSS like "styles" such that you can leave the source alone and change the macros to obtain different effects as required. You will also want to read up about the following commands and switches:  /Define  #if  #IfDef  #IfNDef ═══ 3. Converting From ORB To PPWIZARD ═══ Converting From ORB To PPWIZARD This page will describe the steps required to convert from the "ORB" html preprocessor to PPWIZARD. I am working off the current version of "orbman.txt" as at 1/2/2000 which is for version 1.3 of ORB. This page is being worked on and so is not complete... Since ORB is very simplistic this is a relatively easy task. Most Orb feature map straight across to ppwizard and where limits exist ORB seems to be the most restrictive. You have control over virtually everything that PPWIZARD does, you might wish to check the available options if ppwizard is doing something you disagree with (for example removing leading whitespace). Most of the information below is subject to what options you have set and basically assumes default settings. 1. Orb Comments Orb has block comments using "$comment" and "$endcomment" or "$/*" and "$*/". PPWIZARD does not have block comments except that a #ifdef can be used for this purpose if required. Orb also has "line" comments of "$rem" or "$//", ppwizard has the ";" character (by default). PPWIZARD has "inline" comments as well, if the ";;" sequence is found everything after the last occurance is removed. Some examples: ;--- Include our common code (line comment) ---- #include "common.ih" ;;An inline comment 2. File Inclusion Orb uses "$include" and ppwizard uses #include the variable name is surrounded by "PPWIZARD quotes", for example: #include "common.ih" Instead of using the "ORBPATH" environment variable you can use the "PPWIZARD_INCLUDE" or "INCLUDE" variables. By convention main files have the extension ".IT" and header files have the extension ".IH". 3. Defining Orb Variables Orb uses "$define", "$def" or "$set" commands to define variables. PPWIZARD uses the #define command to create it's variables. You can also use /define from the command line. PPWIZARD is much much more powerful than ORB, see the macros section for more details. An example: #define email dbareis@labyrinth.net.au 4. Using Orb Variables Orb uses "[[Variable]]" when replacing variables, PPWIZARD uses "<$Variable>", for example: #define email dbareis@labyrinth.net.au My email address is "<$email>". Note that PPWIZARD unlike ORB does not quietly ignore "errors" so you will always know if you forget to define something or you spell it incorrectly. If you actually want the string of characters output with no substitution taking place then have a look at PPWIZARD's standard definitions. Another point is that ppwizard's variable names can contain almost any character and be any length, the contents can also span lines and include other ppwizard commands and macros. 5. Removing Orb Variables Orb uses "$undef" command to remove variables. PPWIZARD uses the #undef command to create it's variables. An example: #undef email 6. Conditional Compilation PPWIZARD can do much more than ORB (see the #if command) however when ORB uses "$ifdef" or "$ifndef" then ppwizard uses #ifdef or #ifndef. Orb's documentation does not say if nesting of conditional code is allowed. PPWIZARD allows nesting to any level. An example: #ifdef P_email

My email address is "<$email>". #endif 7. User Defined Errors ORB uses "$error" and ppwizard uses #error, for example: #ifdef P_email #ifndef TRANSLATE_MODE #error "You forgot to define 'TRANSLATE_MODE'!" #endif #endif 8. User Defined Messages ORB uses "$message" or "$msg" to generate messages, ppwizard uses #info and #warning. 9. ORB's $VAL Orb has a "$val" command that ppwizard does not have, you could implement as ppwizard code like: #ifdef email <$email> #elseif Default text #endif The above would create a one new line with either the value of the variable or the default text, if you must have the text "inline" as ORB would then you would need to create a macro. 10. ORB's $TIME Orb has a "$time" command, ppwizard does have a "" variable but it is of a fixed format. In general you will not be happy with this format and will use the "#evaluate" or "#DefineRexx" commands to create your own format. Basically you will be using standard rexx date() and time() routines to build up a time in whatever format you desire, for example: ;--- Capture date/time information (<$CompileTime> --> Friday March 27 1998 at 7:46pm --- #evaluate CompileTime @date('WeekDay') || ' ' || date('Month') || ' ' || substr(date('Sorted'), 7, 2) || ' ' || left(date('Sorted'), 4) || ' at ' || time('Civil')@ ;--- Use the captured date/time ----

This HTML was built at <$CompileTime>. 11. ORB's $TARGET Orb has a "$target" command, ppwizard has a "#output" command which is more powerful but has one major difference, you must also close any file you open. 12. Predefined ORB Variables Firstly you might wish to check out the standard definitions section. A list of ORB variables follows:  orb_platform Have a look at .  orb_vernum Have a look at .  orb_version The closest match is .  orb_generator Have a look at and the /HtmlGenerator switch.  base Have a look at .  Source Have a look at .  Target Have a look at .  datetime_gmt See earlier comments reguarding the "$time" command.  datetime_local See earlier comments reguarding the "$time" command.  NL Have a look at .  SP Have a look at .  OBR Not required.  OBR2 Not required.  CBR Not required.  CBR2 Not required. 13. Line Continuation or Splicing PPWIZARD has line continuation characters. 14. Orb Command Line See PPWIZARD's switch documentation. 15. MAKE Not only can ppwizard be used in make files but ppwizard includes a much more powerful mechanism, see the "/DependsOn" command. ═══ 4. Converting From SSI To PPWIZARD ═══ Converting From SSI To PPWIZARD There is now a PPWIZARD add-on available from the download page which allows you to easily migrate from Server Side Includes (SSI) to PPWIZARD at your own pace. You can have both SSI and PPWIZARD tags in the same files. It will tell you where all SSI tags are located and tell you which ones can't be handled. If a tag can't be handled then you have the option of leaving it in place, dropping it, or outputting an error message into the generated HTML. For more information see the header file in the "SSI" download. ═══ 5. PPWIZARD Command Line ═══ PPWIZARD Command Line Windows NT/2000 users should be able to start PPWIZARD like this: PPWIZARD [[+]InputMask] [@Project] [Options[:parms]] OS/2 users can also use the syntax shown above (make sure PPWIZARD is named "PPWIZARD.CMD"). Windows 95/98/ME and Unix users will probably need to use (and NT/2000 users can use): REGINA PPWIZARD [[+]InputMask] [@Project] [Options[:parms]] As a simple example to build "tryme.htm" from the source file "tryme.it" (supplied with ppwizard) one possible format of the command is: REGINA PPWIZARD tryme.it You should read up about curley codes as these can be used to take care of difficult characters such as spaces, another example is if you had a filename or mask that begins with a minus sign (this normally indicates the start of a command line switch). Spaces can also be handled by surrounding any item on the command line with a range of "quote" characters. This can be very handy in cases where the normally useful double quotes are causing problems (getting dropped by operating system etc). The quote characters you can use include single, double and backwards quotes as well as the "~!#$%^([" characters. If "(" or "[" is used the matching end quote is ")" or "]", otherwise the starting and ending quote characters are the same, valid examples are 'one parm' and [one parm]. Any item that starts with ';' (such as ";/debug) is commented out and is ignored. This should be helpful when testing combinations of switches. Note that Regina looks in the directories mentioned in the "REGINA_MACROS" environment variable for REXX scripts if they are not in the current directory (it does not use the "PATH" environment variable). Unless "ppwizard.rex" is located in a path mentioned in "REGINA_MACROS" then a command such as "regina ppwizard tryme.it" will fail unless PPWIZARD is in the current directory. Of course it will also fail if "regina" is not in one of the directories mentioned in the "PATH" environment or in the current directory. Command Line: InputMask You may specify more than one input mask and they may appear anywhere on the line (however none are processed until after all switches have been). Each mask (anything that does not look like a switch/option) can be the name of a single file or may contain the normal wildcard characters for your operating system ("?" & "*" for OS/2 and Windows). See the documentation for your operating system for more details. Note that with a GETFILELIST hook you can enhance the way that the mask is handled. Note that for some operating systems ppwizard gets passed a pre-expanded list of files and never sees the wildcards, if this is not what you want you can always use curley codes to hide the value from the operating system or regina. If a mask (which may include a path) is preceeded by the "+" character then this indicates that you wish to process all files matching the mask in the indicated (or current) directory and all of it's subdirectories. To specify the location where ppwizard will place the generated output files (current directory by default!) you need to use the /output switch. You may wish to also use a similar specification for the /DependsOn switch if you use it (if not, why not????). Each source file may include other (external) files such as common header files containing your standard definitions and macros. If all input files end in the extension ".X" then the default processing mode is /rexx, the default situation is /html. Each file has an associated base directory, to override the default value (the masks directory) you can use the /BaseDir switch or imbed the "{ENDBASE}" (upper case) string within the InputMask after one of the slashes (the string marks the end of the base directory). Note that if you do mark the base directory this way the Input mask should specify a full path (or begin with '.' or '..' followed by a slash). An example of specifying the base directory would be "c:\projects\source\main\{ENDBASE}subdir1\*.IT". Command Line: Switches / Options All Options begin with '/' or '-' and are executed in the following order: 1. If the optional environment variable "PPWIZARD_OPTIONS" exists these are processed first. 2. If the optional ppwizard project file "ppwizard.ppw" exists then this is processed via the /List switch. You can override any switches specified in the environment variable above if you need to. PPWIZARD first looks in the current directory and then in the same location as the ppwizard runtime if required. 3. Any options specified on the command line. You can override any switches specified in the environment variables or project files above if you need to. Normally files or options are separated by spaces, if the file or option needs to contain spaces then you can surround it by double quotes. If you use double quotes the quoted value must not contain double quotes (encode with "{x22}"). Available switches are: 1. /#Include 2. /$Trace 3. /**/ 4. /@Extn 5. /BaseDir 6. /Beep 7. /CGI 8. /Color 9. /ConsoleFile 10. /Copy 11. /CopyRight 12. /CrLf 13. /Debug 14. /DebugChars 15. /DebugCols 16. /DebugTime 17. /Define 18. /DeleteOnError 19. /DeletePrev 20. /DependsOn 21. /DependsOnComplete 22. /DependsOnWarnings 23. /DropFiles 24. /ErrorFile 25. /Exclude 26. /Exec 27. /FileNames 28. /FilterInput 29. /FilterOutput 30. /GetEnv 31. /HideCmd 32. /Hook 33. /Html 34. /HtmlGenerator 35. /Inc2Cache 36. /IncludePath 37. /Info 38. /List 39. /Making 40. /OnERROR 41. /OnOK 42. /Option 43. /Other 44. /Output 45. /OutHeader 46. /Pack 47. /RedirMethod 48. /RegSyntax 49. /Rexx 50. /Sleep 51. /SpellAddWord 52. /SpellCheck 53. /SpellShowAll 54. /Template 55. /UNC 56. /Validate 57. /WarningsRc 58. /XSlash LONG COMMAND LINES / CONFIGURATION FILES PPWIZARD supports storing configuration information in the following ways: 1. Environment Variables Using the /GetEnv switch you can easily retrieve previously stored command line options (possibly set up in "config.sys" or windows registry). 2. In List File Using the /List switch you can easily retrieve command line options from a configuration file. A major advantage of a "list" file is that you do not have to handle characters such as '>' as you would have to if it came from the command line. Note that ppwizard will automatically read in any file named "ppwizard.ppw" (default project file). RETURN CODES  A return code of 0 indicates success.  A return code of 1 indicates success (with warnings) and /WarningsRc was not used to turn them off.  Any other value indicates an error occurred. The /ErrorFile and /ConsoleFile can help you capture any text output by ppwizard which can be particulary useful if you don't work from the command line. EXAMPLE This example has the following attributes: 1. Make file functionality without the hassle. 2. All source files have an extension of ".IT" (headers use ".IH"). 3. All output to have the extension ".html" and go into the "OUT" directory. +-[ MAKEIT.CMD ]------------------------------------------------+ | @echo off | | md OUT >nul 2>&1 | | md OUT\DEPEND >nul 2>&1 | | ppwizard %1.IT /Output:OUT\*.html /DependsOn:OUT\DEPEND\*.DEP | | if errorlevel 1 echo ERROR: Command failed! | +---------------------------------------------------------------+ Example - Redirection Ppwizard (or any other program) can at times generate quite a lot of output. When /Debug is used you will definitely wish to "redirect" the output into a file, the following is an example which would work in virtually all operating systems (including linux bash shell - change switch characters to '-'!): [regina] ppwizard index.it /Output:OUT\*.htm /Debug > OUT\output.TXT 2>&1 If the redirection example does not work you will need to read the documentation for the operating system you are using to determine the correct method. If this failed on Windows NT or 2000 (one of the 1,234,657 bugs!) then you will need to specify the regina interpreter first ("regina ppwizard" etc). ═══ 5.1. Project Files ═══ Command Line: @Project PPWIZARD allows you to put all or some of your file specifications or switches into project (configuration) files with a default file extension of ".ppw" and easily refer to them from the command line. PPWIZARD uses FindFile() to search for project files. Basically the project facility is a "smarter" version of the /List functionality (and easier to type!). If you need to refer to project files in specific directories then the "/list" switch is required. PPWIZARD automatically looks for a specific project file (called "ppwizard.ppw"). By default if all input files have the same extension then ppwizard will also try to load an extension based project file, see the /@EXTN switch for more information. See the /List switch for more details on the file format, but here is a sample configuration file (lets call it "all.ppw"): ;----------------------------------------------------------------------- ;--- This file builds HTML for all "*.IT" files in current directory --- ;----------------------------------------------------------------------- *.IT ;;Only build files matching this mask /DependsOn:DEP\*.DEP ;;Only rebuild files that need it (new or modified) /Output:OUT\*.htm ;;I like files generated into the "out" directory and with the ".htm" extn To use the "all.ppw" file shown above you could say: ppwizard @all As shown above all "*.it" files will be processed if we wished to process a single file but still make use of the project file for the options then you would need to make use of the /DropFiles switch. As documented for "/list" nothing stops one list or project file from loading others. ═══ 5.2. Curley Codes ═══ Curley Codes These codes are used to specify characters that might otherwise be incorrectly interpreted by either your operating system or PPWIZARD. If you know the ASCII code of a character (in hex) you can encode it, for example "{x20}" represents a space. If a code looks invalid then it is ignored. The following are codes for some of the more difficult command line characters you are likely to need: ┌───────┬───────┬────────────────┐ │Ascii │Code │Description │ ├───────┼───────┼────────────────┤ │32 │{x20} │Space │ ├───────┼───────┼────────────────┤ │33 │{x21} │! │ ├───────┼───────┼────────────────┤ │34 │{x22} │" (double quote)│ ├───────┼───────┼────────────────┤ │35 │{x23} │# │ ├───────┼───────┼────────────────┤ │36 │{x24} │$ │ ├───────┼───────┼────────────────┤ │37 │{x25} │% │ ├───────┼───────┼────────────────┤ │38 │{x26} │& │ ├───────┼───────┼────────────────┤ │39 │{x27} │' (single quote)│ ├───────┼───────┼────────────────┤ │40 │{x28} │( │ ├───────┼───────┼────────────────┤ │41 │{x29} │) │ ├───────┼───────┼────────────────┤ │42 │{x2A} │* │ ├───────┼───────┼────────────────┤ │43 │{x2B} │+ │ ├───────┼───────┼────────────────┤ │44 │{x2C} │, │ ├───────┼───────┼────────────────┤ │45 │{x2D} │- │ ├───────┼───────┼────────────────┤ │46 │{x2E} │. (dot) │ ├───────┼───────┼────────────────┤ │47 │{x2F} │/ │ ├───────┼───────┼────────────────┤ │58 │{x3A} │ │ ├───────┼───────┼────────────────┤ │59 │{x3B} │; │ ├───────┼───────┼────────────────┤ │60 │{x3C} │< │ ├───────┼───────┼────────────────┤ │61 │{x3D} │= │ ├───────┼───────┼────────────────┤ │62 │{x3E} │> │ ├───────┼───────┼────────────────┤ │63 │{x3F} │? │ ├───────┼───────┼────────────────┤ │64 │{x40} │@ │ ├───────┼───────┼────────────────┤ │91 │{x5B} │[ │ ├───────┼───────┼────────────────┤ │92 │{x5C} │\ │ ├───────┼───────┼────────────────┤ │93 │{x5D} │] │ ├───────┼───────┼────────────────┤ │94 │{x5E} │^ │ ├───────┼───────┼────────────────┤ │95 │{x5F} │_ (underscore) │ ├───────┼───────┼────────────────┤ │96 │{x60} │` │ ├───────┼───────┼────────────────┤ │123 │{x7B} │{ │ ├───────┼───────┼────────────────┤ │124 │{x7C} │| │ ├───────┼───────┼────────────────┤ │125 │{x7D} │} │ ├───────┼───────┼────────────────┤ │126 │{x7E} │~ │ └───────┴───────┴────────────────┘ ═══ 5.3. /BaseDir ═══ Switch /BaseDir[:SomeAbsoluteDirectory] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. Each input file has an associated "base directory", if your input mask did not specify that subdirectories were being processed then this directory is the directory the file is in otherwise it is the directory of the specified mask (of course these values may be the same for all or some files). The value supplied on this switch overrides all following default base directories for input filemasks. The value should have a terminating slash and must begin any filemasks you attempt to use or ppwizard processing will abort. You can restore normal processing by using "/BaseDir" without a directory. The directory you use must be an absolute directory or the result will not be correct. There are some simple relative paths that PPWIZARD can convert to absolute such as those starting with '..' and '.' followed by a slash. You would probably never wish or need to override the base directory value unless you normally process a whole tree and now wish to process a subtree as if the whole tree were being processed. The value can be accessed with the "" definition. Alternative An alternative way of specifying the base directory is to imbed the "{ENDBASE}" (upper case) string within the filemask after one of the slashes (the string marks the end of the base directory). ═══ 5.4. /Beep ═══ Switch /Beep[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. You can determine if beeps occur in some situations such as ppwizard detecting errors. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.5. /CGI ═══ Switch /CGI:LogFile This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This command changes the way PPWIZARD works to allow it to be used as a web server based CGI program (or part of a bigger CGI process). The output goes to stdout and what would normally go to stdout is prevented from going there. If the optional "LogFile" is not specified then all status, debug and error output is dropped. If you need to see this you would specify the name of a file. If the filename includes "?" then a "random" 8.3 filename (no path) is chosen and replaces the "?". If the ppwizard output is not part of a larger process then you may want to make use of the "" variable. Being a CGI script (or part of one) you would want your code to be as fast as possible, I highly recommend you read the "performance" documentation. CGI OPTIONS You may /define, #define or #evaluate the following variables to control the output which occurs in the case of a fatal error (the default is to display the information):  CGI_FATAL_MY_MESSAGE_ONLY Define this variable if you don't want any details of the message to be displayed in the HTML output. Leave this variable empty so as not to indicate an error (other than truncated output!) or supply the HTML codes and text you wish displayed.  CGI_FATAL_HEADER This variable controls the HTML codes that are sent to stdout before the lines that contain the details of the error. It is recommended that these codes include "

" or similar to retain the line 
          formatting on error lines. 

         CGI_FATAL_TRAILER 
          This variable controls the HTML codes that are sent to stdout after 
          the lines that contain the details of the error.  The codes will 
          usually reverse those you specified for use before the error details. 

 Example 

 The following examples show the options being specified on the command line, 
 it is probably better to have any common options specified in CONFIG.SYS on 
 the web server. 

      ppwizard EmailForm.TEM /CrLf /CGI
      ppwizard EmailForm.TEM /CrLf /CGI:LOGS\LAST.LOG
      ppwizard EmailForm.TEM /CrLf /CGI:LOGS\?


═══ 5.6. /Color ═══

Switch /Color[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

You can determine if colors are used in displayed output.  Useful if 
redirecting output to log files (or you just hate colors!). 

If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise 
one of the following values is expected: 

         Y 
         N 
         YES 
         NO 

 For colors to work the session must support ANSI color strings. OS/2 does this 
 by default.  NT does not seem to. 


═══ 5.7. /ConsoleFile ═══

Switch /ConsoleFile:[+]FileName 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

Sometime it would be handy to duplicate all the PPWIZARD output that goes to 
the console to a file. This is particularly true if you are not working from a 
command prompt or PPWIZARD is generating heaps of output as it will if debug 
mode is on (e.g. you used the /Debug switch). 

Of course redirection of the console output is another way the output can be 
captured particularly if you don't actually want the output sent to the 
console. 

By default console output does not go to a file. If you just wish to see an 
error output then have a look at the /ErrorFile switch. 

The environment variable "PPWIZARD_CONSOLEFILE" is an alternative way to set 
the filename. It takes the desired filename (not a file mask). If the filename 
begins with "+" then the file is appended to and not deleted every time 
ppwizard starts. 

If no parameter is supplied on this switch then console output is not sent to a 
file otherwise the format is exactly the same as that described for the 
environment variable. 

Note that this switch can only take effect from the time that ppwizard is 
processing the command line and has seen the switch, so it can not handle any 
console output before this. You may wish to use the environment variable to set 
it and in any case use this switch as early as possible on the command line. 

Rexx tracing performed by the interpreter can't be sent to the file as I 
recommend PPWIZARD tracing in any case you may not be using it. 

Do not simply use the rexx "say" command or the "charout" call to send output 
to standard out because if you do it will not appear in the console file, you 
need to use the Say() and Chars() calls instead. 

EXAMPLE #1 

In the following example we use the switch to specify a file name and directory 
for the console file and specify that we wish to append to the end of the file 
rather than delete it every time ppwizard begins: 

    ppwizard *.IT /ConsoleFile:+out\PPWIZARD.CON /Output:OUT\*.html

EXAMPLE #1 

In the following example we use the switch to specify a file name and directory 
for the console file and specify that we wish ppwizard to start with a clean 
file, we also don't wish to see any output: 

    ppwizard *.IT /ConsoleFile:out\PPWIZARD.CON /Output:OUT\*.htm > nul 2>&1

Note that the redirection syntax may differs between operating systems (it is 
not a ppwizard feature). Windows 95/98 users are basically using DOS and so the 
"2>&1" bit can't be used but the example can be used in most other operating 
systems. 


═══ 5.8. /Copy ═══

Switch /Copy 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This processing mode switch indicates that you simply want the input file 
copied from one place to another (source and destination filenames don't need 
to have the same name). 

All following input masks are processed in "COPY" mode, the "/output" switch 
determines the destination directory and filename (it would normally include 
"*.*"). 

This can be used to syncronise .GIF, .JPG or other binary files with a local 
homepage image. Note that you would normally also use the /DependsOn switch so 
that the copy only occurs when the file has changed! PPWIZARD will not 
particularly care whether the source file time is newer or older (or in fact 
the same) than the output file, it simply cares whether the source file has 
changed (exactly what you'd like). 

This switch can be used any number of times and will affect all input masks 
that follow. For backwards compatability, if an input mask is found before any 
processing mode switch then the last instance of a processing mode switch is 
used these. 

EXAMPLE OF USE 

You might already have a directory tree which is an image of your web site 
(contains images and html etc). This is useful for local testing and simplifies 
things when updating your web server. 

 you will pass through PPWIZARD). 

d does not care what extensions you use - as long as you don't forget which is 
which!). 

Note that if you wish to use graphical HTML editors you should have a look at 
the "/HideCmd" switch. 

The use of separate tree, the "/COPY" switch and "/HideCmd" would be a good 
approach if you wish non-technical people to maintain the source (or maybe 
while you get used to PPWIZARD and test it out). 

tories and deleting obsolete files or directories. If you use WINDOWS I have a 
free self installing download that makes it extremely easy to setup (unlike the 
official download...). 


═══ 5.9. /CopyRight ═══

Switch /CopyRight[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

By default a 3 line copyright message is displayed, this allows you to turn the 
message off. 

Note that on error or debug mode being on it is output anyway. 

If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise 
one of the following values is expected: 

         Y 
         N 
         YES 
         NO 


═══ 5.10. /CrLf ═══

Switch /CrLf[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch can be used to vary the line termination characters. These are 
initialized to newline on unix and carriage return plus linefeed elsewhere. 

You can "compress" html on OS/2 and Windows systems a bit more by removing the 
carriage return as html browsers don't need them, this way you'd save one byte 
per line. 

If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise 
one of the following values is expected: 

         Y 
         N 
         YES 
         NO 


═══ 5.11. /Debug ═══

Switch /Debug 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This option can be useful in determining what is going wrong when you don't get 
the output you expected. 

The output is fairly easy to understand and aims to actually teach (or help you 
to understand) certain commands (such as #import). 

This switch is handy if you really have no idea where something is going wrong, 
if you have an idea of where the fault lies then it is much smarter to add 
#debug commands where required so as to speed up ppwizard execution and reduce 
the volume of output. Another way of reducing debug output is via the 
DebugLevel option. 

To get the maximum output use the switch as early as possible on the command 
line. 

If you wish to report a problem with ppwizard then please use this switch and 
send the output zipped along with any other details. 

Note that if this command line switch is used you can no longer turn debug mode 
on and off with the #debug command. 

The following switches are also simulated: 

         /INFO 
         /COLOR:N 
         /BEEP:N 


═══ 5.12. /DebugChars ═══

Switch /DebugChars:List 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch allows you to modify the following debug 'markers': 

       1. Left Quote 
          This allows you to change the way ppwizard displays a left "quote" in 
          debug mode. 

       2. Right Quote 
          This allows you to change the way ppwizard displays a right "quote" 
          in debug mode. 

       3. New Line 
          This allows you to change the way ppwizard displays a new line 
          character. 

 If the supplied list is empty then the defaults are restored otherwise it 
 specifies the values for as many comma seperated items as are supplied in the 
 list (items assigned in the order shown above). 

 An item can be: 

         A value of "-1" means use an empty string (no characters). 

         A decimal number is the ASCII code of the single character you wish. 

         Anything else is a character or characters that you wish. This can of 
          course include normal command line hexadecimal codes. 

 This switch can be handy as the default characters could easily be misread as 
 normal characters. If your viewer supports some of the extended characters 
 (below the space or above ASCII 127) then this can make debug output much 
 easier to read. 

 Display List In Your Viewer 

 The following code allows you to create a list of possible codes for you to 
 examine in the particular viewer that you will be using to look for good 
 distinct characters. These will/may have to be changed if you change your 
 viewer. 

 Just cut and paste the following: 

      #define    DisplayX  call Say left(d2c(x),6) || left(x,9) || '{x' || d2x(x) || '}'
      #DefineRexx ''
         ;--- Title ---------------------------------------------------------------
         call Say '';
         call Say 'CHAR  DECIMAL  HEX STRING'
         call Say '~~~~  ~~~~~~~  ~~~~~~~~~~'

         ;--- Do all but ASCII code 0 and 9, 10,13 --------------------------------
         do  x = 1 to 255
             if  x <> 9 & x <> 10 & x <> 13 then
             do
                 <$DisplayX>
             end;
         end;

         ;--- Now do ASCII 0 (some editors/viewers will NOT HANDLE THIS!) ---------
         x = 0; <$DisplayX>
         call Say '';
      #DefineRexx

 EXAMPLE 

 The following characters look good in the version of notepad I'm using. 

      PPWIZARD /DebugChars:187,171,165


═══ 5.13. /DebugCols ═══

Switch /DebugCols:0OrMaxNumberCols 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

PPWIZARD can output some extremely long lines when debug is on (/Debug used 
etc). This switch allows you to set the longest line allowed. A line if 
truncated will actually be a bit longer as the fact that a line is truncated if 
too long is appended to the end of the line. 

If "0" is passed then there is no limit on the line length otherwise it must be 
a positive value. 


═══ 5.14. /DebugTime ═══

Switch /DebugTime[:NoOrFormat] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

By default ppwizard outputs the elapsed time (short display format) at the 
start of any debug line it outputs. This option allows you to select a longer 
format (HH:MM:SS.99) or turn off time generation altogether. 

Outputting the time can help you identify areas of code that may be taking 
longer than you'd expect to execute. 

The parameter should be one of the following values: 

         N or NO 

         L or LONG 

         S or SHORT 

 Note that ppwizard is optimised for fast execution with debug turned off, and 
 in fact may perform extra work when debug is on (on the assumption that 
 execution time is not an issue). For these reasons you should use the timings 
 you obtain as a guide only. 

 Note that a regina bug (in versions less than 2.0) prevents this from working 
 correctly at this time. 


═══ 5.15. /Define ═══

Switch /Define:Variable=Contents 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This command sets variables (like #define), but from the command line. This 
would typically be done to pass information to the script via the command line 
(possibly version number information or similar) removing the requirement to 
edit your source code. 

You can set as many variables as you wish by using the switch once for each 
variable. 

If the contents needs to include a space you should use "" instead. 

I recommend that if you use this switch you also ensure that you are also using 
the *CmdLine" dependancy type so that if you change the value of the switch 
then a rebuild will occur (look at generated dependancy files if unsure). 

EXAMPLE 

Define 2 variables 

    ppwizard 1.in /output:out\*.out /CrLf /Define:OpSys=OS/2

In your code you could do: 

    #if '<$OpSys>' = 'OS/2'
        ...
    #elseif
        ...
    #endif


═══ 5.16. /DeleteOnError ═══

Switch /DeleteOnError[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

By default PPWIZARD deletes any generated files when an error occurs. This 
makes it more friendly in normal MAKE files which will then correctly restart 
the build process. You may wish to promote warnings to errors using the 
"Warnings" option. 

If not disabled, PPWIZARD will on error delete all files that it knows about, 
so in some cases it relies on you having correctly indicated output 
dependancies with the #DependsOn command or AddOutputFileToDependancyList() 
routine. PPWIZARD will ignore file deletion errors (what can it do?). 


═══ 5.17. /DeletePrev ═══

Switch /DeletePrev[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

By default PPWIZARD deletes any files generated on a previous build before 
starting the next build. The build will fail if a file can't be deleted. 

This switch is useful where a single input file can produce many output files. 
In these cases obsolete files can easily build up in the output directories. 

The deletion process uses the dependancy file built by the previous build so 
you must also be using the "/DependsOn" switch for older files to be deleted. 

If you were to rely on this switch deleting older files then you would also 
wish to use the "/DeleteOnError" switch. 

Obviously this process is not perfect, if the machine traps and reboots during 
a build nothing will delete those files that were generated. Also the complete 
deletion of a obsolete input file does not cause the deletion of the associated 
output files (yet)... 

To cover all bases you could generate into a unique directory (or generate 
distinctive filenames) for those processes that generate multiple files and use 
a BEFORE "/Hook" switch to clean up the directory where a rebuild is required. 

WARNING 

I have still not figured out a clean/easy way of deleting obsolete dependancy 
and output files where the input file is removed. When I do so this switch is 
likely to be affected (possibly different parameters or removed). 


═══ 5.18. /DependsOn ═══

Switch /DependsOn:[-]EditMask 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This option requires a parameter which controls how the "InputFile" parameter 
is transformed into the name of a dependancy file.  The default is that there 
is no dependancy file (therefore dependancies are not checked).  If you use 
dependancy files then the output is only built if required (a source file has 
changed). 

Unless you preceeded the EditMask parameter with a '-' the dependancy checking 
progress is displayed. 

PPWIZARD knows how to create a complete dependancy file unless you access files 
directly (via rexx with "linein()", "lineout(), "charin()" or similar 
functions). If you do directly access a file you will need to help ppwizard by 
using the #DependsOn command or the AddInputFileToDependancyList() or 
AddOutputFileToDependancyList() rexx functions. 

An edit mask is basically much like a file (with path if required) and will 
contain zero or one special characters as follows: 

       1. *.* or {$SHORT} 
          This gets replaced with the short filename (no path) of the current 
          input file.

       2. * or {$BASE} 
          This gets replaced with the short filename (less path and extension) 
          of the current input file.

       3. {$FULL} 
          This gets replaced with the full filename (with path) of the current 
          input file.

       4. ? or {$PATH} 
          This gets replaced with the path (including terminating slash) of the 
          current input file. This is most likely to be of use if you want to 
          position generated files relative to the input file and your mask 
          scans subdirectories. For example "?OUT\*.HTM".

       5. {$path} 
          This allows you to set up a separate tree for generated filenames, 
          the input mask and file are examined and the relative path extracted, 
          the result is either blank ('') or a relative path that ends with a 
          path separator. Note for this to work the input mask must either use 
          an absolute path, begin with '.' or '..' followed by slash or not 
          have a path attached at all otherwise ppwizard will abort. It would 
          be pointless to use this sort of path unless subdirectories are being 
          scanned. You may wish to investigate the /BaseDir switch.

 Note that unix type operating systems will probably have problems with "$path" 
 etc (to unix this means replace with the "path" environment variable's 
 contents). You need to hide or escape the dollar sign, so use either 
 "{x24}path" or "\$path" instead.

 The "EditMask" can be absolute or relative (your exact circumstances will 
 determine your choice). 

 Note that resultant relative filenames are always relative to the current 
 directory. 

 While you control the case of the mask you can't control the case of the part 
 that replaces the '*'.  What you can do is ensure the whole name is either in 
 upper or lower case with the /FileNames switch. 

 This switch can be used any number of times and will affect all input masks 
 that follow. For backwards compatability, if an input mask is found before 
 this switch then the very last instance of this switch is used for these. 

 EXAMPLE 

 In the following example the command will check/create a file called 
 "OUT\DEPEND\IN.DEP": 

      +-[ MAKEIT.CMD ]------------------------------------------------+
      | @echo off                                                     |
      | ppwizard IN.IT /Output:OUT\*.html /DependsOn:OUT\DEPEND\*.DEP |
      | if errorlevel 1 echo ERROR: Command failed!                   |
      +---------------------------------------------------------------+


═══ 5.19. /DependsOnComplete ═══

Switch /DependsOnComplete[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch alters the way "/DependsOn" works. 

Normally ppwizard is very strict in its input dependancy checking in that it 
puts itself and any spelling dictionaries used in the list as well as checking 
command line switches. This means that when one of these items changes 
everything gets remade. While the safest option is to leave it on you may wish 
to turn it off. 

Note that this switch controls the building of the dependancy file. Existing 
dependancy files will need to rebuild at least once under the new setting for 
everything to work as you wish, for this reason you may wish to delete any 
existing dependancy files when you change the setting. 

If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise 
one of the following values is expected: 

         Y 
         N 
         YES 
         NO 


═══ 5.20. /DependsOnWarnings ═══

Switch /DependsOnWarnings[:YesOrNo] 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch alters the way "/DependsOn" works. 

By default ppwizard will not generate the dependancy file if warnings are 
generated. Warnings are considered to be abnormal conditions which are not 
serious enough to be considered to be an error. You are expected to remove or 
prevent the warnings. 

By using this switch and specifying "NO" you are indicating that the dependancy 
file should be generated even if warnings are generated. 

If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise 
one of the following values is expected: 

         Y 
         N 
         YES 
         NO 


═══ 5.21. /DropFiles ═══

Switch /DropFiles 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch simply tells PPWIZARD to forget any filemasks it has been told 
about. 

One reason for using in might be that you have set up a project containing your 
favorite options and a default mask (lets say "*.IT"), if you wished to use the 
project file but not process "*.IT" then this flag can be used as shown in the 
example below: 

    ppwizard @MyProj /DropFiles some*.it


═══ 5.22. /Exclude ═══

Switch /Exclude:FileMask 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

Sometimes you may wish to process most files with a few exceptions, this switch 
allows you to specify those exceptions.  The switch may be used as many times 
as required. 

    ppwizard *.IT /Exclude:TEST*.IT /Exclude:TRY?.IT /Output:OUT\*.html


═══ 5.23. /Exec ═══

Switch /Exec:[{RcTest}][!]Command 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This switch allows you to specify a command which will be executed immediately. 

Normally the command output is hidden and captured if in debug mode. To see the 
output preceed the command with the '!' character. 

If "RcTest" is not supplied then the return code is ignored otherwise it is a 
rexx expression where the rexx variable "CmdRc" holds the commands return code. 
A boolean result is expected with TRUE meaning the validation was successful. 


═══ 5.24. /ErrorFile ═══

Switch /ErrorFile:[+]FileName 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

By default ppwizard duplicates any displayed error message to a file called 
"PPWIZARD.$$E" in the current directory. Again by default this file is not 
deleted when ppwizard starts but is appended to as required. This facility is 
very useful for people who don't like the command prompt and use windows 
explorer or similar (as it can be difficult tell what caused a build failure). 

You can turn the error file generation off or change the filename, the 
directory it gets created in or whether or not it gets deleted or appended to. 

The environment variable "PPWIZARD_ERRORFILE" is an alternative way to set the 
filename. It takes the desired filename (not a file mask). If the filename 
begins with "+" then the file is appended to and not deleted every time 
ppwizard starts. 

If no parameter is supplied on this switch then error file generation is turned 
off otherwise the format is exactly the same as that described for the 
environment variable. 

Note that this switch can only take effect from the time that ppwizard is 
processing the command line and has seen the switch, so it can not handle any 
errors that occur before this. You may wish to use the environment variable to 
set it and in any case use this switch as early as possible on the command 
line. 

Another thing to keep in mind is that output to the file only begins after 
ppwizard has detected an error so some "context" information may be lost in 
which case you should have a look at the /ConsoleFile switch as well. 

EXAMPLE 

In the following example we use the switch to specify a new name and directory 
for the error file and we don't want to keep appending to it: 

    ppwizard *.IT /ErrorFile:out\PPWIZARD.ERR /Output:OUT\*.html

This shows how the error file generation can be turned off: 

    ppwizard *.IT /ErrorFile /Output:OUT\*.html


═══ 5.25. /FileNames ═══

Switch /FileNames:TranslateType 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

Normally the case of output filenames are not modified, you can override this 
behaviour with this command line switch.  It requires either "Upper" or "Lower" 
as a parameter. 


═══ 5.26. /FilterInput ═══

Switch /FilterInput:RexxCmdFile 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This will probably be a rarely used option.  This switch allows you to 
translate file input a line at a time.  The mechanism provides the filter 
enough information to perform complex processing (in case required).  Your 
filter routine will return the possibly changed line or lines. 

In most cases it would probably be easier to write a translation procedure as a 
separate step before PPWIZARD is invoked (however sometimes this may not be 
practical). 

The rexx filter code you identify will be passed the following arguments: 

       1. The literal 'I' indicates that input is being filtered. 

       2. The line as read by rexx (still has comments and all whitespace). 

       3. The name of the file where the line came from. 

       4. The line number of the source file being processed (first line is 1). 

       5. The overall input line number (counter). 

       6. The newline character you should use if returning more than one line. 

 The following environment variables are also available for use: 

       1. PPWIZARD_VER_II 
          This variable contains the version number of the interface used by 
          this program.  This version number will only change when PPWIZARD has 
          been modified in such a way that existing input filters could break. 
          It is recommended that you validate the interface in your filter. 

       2. PPWIZARD_DEBUG 
          This variable tells you the current debug state ('Y' means on).  This 
          can be modified by the #debug command or the "/debug" command line 
          switch. 

       3. Your Own Variables 
          You can create your own state variables in the environment. 

 I have a need where each input line is encrypted to prevent tampering by 
 users, the source is divided over many header files. For a number of reasons I 
 do not wish to perform a separate step to get the files in the clear.  This 
 switch is my generic solution. 

 WHAT YOU RETURN 

       1. You may modify the passed line in any way you wish and return the 
          result. 

       2. You may pass back more than one line by separating the lines with the 
          passed newline character.  This allows you to insert macros or 
          #include instructions. 

       3. You may drop a line altogether by returning the string value 
          "d2c(0)". 

       4. You may indicate an error by returning "d2c(0)" followed the error 
          message, processing will stop. 

 EXAMPLE OF INPUT FILTER 

  /************************************************/
  /* Stupid non-useful example of an input filter */
  /************************************************/

  /*--- Get ALL parameters ----------------------------------------------------*/
  FilterType   = arg(1);
  TheLine      = arg(2);
  FromFile     = arg(3);
  FromFileLine = arg(4);
  TotalLine    = arg(5);
  NewLine      = arg(6);

  /*--- Check ONCE if on correct interface ------------------------------------*/
  if  TotalLine = 1 then
  do
     /*--- Filter written to interface version "98.131" --------------------------*/
     WrittenToFilterVer = "98.131";
     CallersVer         = GetEnv("PPWIZARD_VER_II");
     if  CallersVer <> WrittenToFilterVer then
         return(d2c(0) || 'FILTERIN: Interface written to version ' || WrittenToFilterVer || ' (found ' || CallersVer || ')' );
  end;

  /*--- Get current debug state (output input line if debug is on) ------------*/
  DebugOn = GetEnv("PPWIZARD_DEBUG");
  if DebugOn = 'Y' then
     say 'FILTERIN: #' || TotalLine || ' -> ' || TheLine;

  /*--- Process the input -----------------------------------------------------*/
  if  TotalLine = 1 then
  do
     /*--- We wish to drop the 1st line ---------------------------------------*/
     if  DebugOn = 'Y' then
         say '          We are dropping this line';
      return(d2c(0));
  end;
  else
  do
     /*--- Now either insert a line (if 4th) or return line unchanged ---------*/
     if  TotalLine = 4 then
         return(TheLine || NewLine || 'This line was inserted after the 4th line input line!');
     else
         return(TheLine);
  end;


  /*===========================================================================*/
  GetEnv:
  /*                                                                           */
  /* arg(1) : Name of environment variable.                                    */
  /*===========================================================================*/
     return( value(arg(1),,'OS2ENVIRONMENT') );


═══ 5.27. /FilterOutput ═══

Switch /FilterOutput:RexxCmdFile 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This will probably be a rarely used option.  This switch allows you to 
translate all generated lines a line at a time.  The mechanism provides the 
filter enough information to perform complex processing (in case required). 
Your filter program actually writes all output lines. 

In most cases it would probably be easier to write a translation procedure as a 
separate step after PPWIZARD has completed (however sometimes this may not be 
practical). 

The rexx filter code you identify will be passed the following arguments: 

       1. The literal 'O' indicates that output is being filtered. 

       2. The generated line without terminating newline. 

       3. The name of the output file. 

       4. The number of lines already generated to the file (starts at 0). 

       5. The overall number of lines generated. 

       6. The newline character(s) that need to terminate each line that you 
          write.  The value of the newline may change if /CrLf is used. 

 The following environment variables are also available for use: 

       1. PPWIZARD_VER_OI 
          This variable contains the version number of the interface used by 
          this program.  This version number will only change when PPWIZARD has 
          been modified in such a way that existing output filters could break. 
          It is recommended that you validate the interface in your filter. 

       2. PPWIZARD_DEBUG 
          This variable tells you the current debug state ('Y' means on).  This 
          can be modified by the #debug command or the "/debug" command line 
          switch. 

       3. Your Own Variables 
          The filter program can create its own state variables in the 
          environment, this is demonstrated in the example further on.  You can 
          also set environment variables with the built in SetEnv routine. 

 WHAT YOU RETURN 

       1. If successful you should return the string "OK:" followed by the 
          number of lines you wrote to the output file.  For example you would 
          return "OK:0" if you dropped the passed line. 

       2. Any string that does not begin with "OK:" indicates an error. The 
          message will be displayed and processing will stop. 

 EXAMPLE OF OUTPUT FILTER 

  /*************************************************/
  /* Stupid non-useful example of an output filter */
  /*************************************************/

  /*--- Get ALL parameters ----------------------------------------------------*/
  FilterType   = arg(1);
  TheLine      = arg(2);
  ToFile       = arg(3);
  ToFileLine   = arg(4);                                     /* Written so far */
  TotalLine    = arg(5);                                     /* Written so far */
  NewLine      = arg(6);

  /*--- Check "ONCE" if on correct interface (Actually checked twice) ---------*/
  if  TotalLine = 0 then
  do
     /*--- Filter written to interface version "98.132" -----------------------*/
     WrittenToFilterVer = "98.132";
     CallersVer         = GetEnv("PPWIZARD_VER_OI");
     if  CallersVer <> WrittenToFilterVer then
         return( 'FILTEROUT: Interface written to version ' || WrittenToFilterVer || ' (found ' || CallersVer || ')' );
  end;

  /*--- Get current debug state (output input line if debug is on) ------------*/
  DebugOn = GetEnv("PPWIZARD_DEBUG");
  if DebugOn = 'Y' then
     say 'FILTEROUT: #' || TotalLine+1 || ' -> ' || TheLine;

  /*--- If first line drop (this is complicated by line counters not changing!)*/
  if  TotalLine = 0 then
  do
     /*--- Only drop the first "first" file! ----------------------------------*/
     if  GetEnv('FiltOut_0') = '' then
     do
         /*--- We wish to drop the 1st line -----------------------------------*/
         if  DebugOn = 'Y' then
             say '          We are dropping the first line of output';
         call SetEnv 'FiltOut_0', 'Line 0 dropped';
         return("OK:0");
     end;
  end;

  /*--- All lines reversed (except inserted 5th) ------------------------------*/
  NumberOfLines = 1;
  ToWrite       = reverse(TheLine);
  if  TotalLine = 3 then
  do
     /*--- We are inserting a line (generating 2) -----------------------------*/
     NumberOfLines = 2;
     ToWrite       = ToWrite || NewLine || 'This line was inserted after the 4th output line line!';
  end;

  /*--- Output the data -------------------------------------------------------*/
  if  0 <> charout(ToFile, ToWrite || NewLine) then
     return('Write to "' || ToFile || '" failed!');
  else
     return("OK:" || NumberOfLines);




  /*===========================================================================*/
  GetEnv:
  /*                                                                           */
  /* arg(1) : Name of environment variable.                                    */
  /*===========================================================================*/
     return( value(arg(1),,'OS2ENVIRONMENT') );




  /*===========================================================================*/
  SetEnv:
  /*                                                                           */
  /* arg(1) : Name of environment variable.                                    */
  /* arg(2) : New Value.                                                       */
  /*                                                                           */
  /* Returns original value of the environment variable.                       */
  /*===========================================================================*/
     return( value(arg(1),arg(2),'OS2ENVIRONMENT') );


═══ 5.28. /GetEnv ═══

Switch /GetEnv:EnvVarName 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This allows you to specify an environment variable which must exist and whose 
value is more PPWIZARD command line parameters. 

This switch could be used to handle long command line, it effectively allows 
you to have an infinitely long command line since the included contents can 
itself refer to other environment variables. 


═══ 5.29. /HideCmd ═══

Switch /HideCmd:HideTemplate 

This is a PPWIZARD command line switch. You can set up your own default 
switches in the "PPWIZARD_OPTIONS" environment variable or in project files. 

This allows you to hide ppwizard commands, macros references or in fact 
anything between start and end tags that you specify. 

This could be useful for a number of reasons but probably the most common would 
be to hide ppwizard tags from a WYSIWYG html editor or browser. This would 
allow you to view the template of the web page without distractions (the 
browser will not display comments!). 

The "HideTemplate" indicates both the start and end markers with "{?}" marking 
the position of the hidden command, exceptions are: 

       1. HTML[] 
          This is shorthand for "". This is basically HTML comments 
          with extra square brackets. 

 I highly recommend that you do not try to use the SSI format as this can only 
 confuse people. 

 Example - Use of switch 

 In this case we wish to hide all ppwizard items within "<%" and "%>" tags, the 
 curley codes are used so as to be able to safely specify the "<" and ">" 
 characters (redirection characters in most operating systems) on the command 
 line. 

      /HideCmd:{x3C}%{?}%{x3E}

 To an ASP/JSP friendly GUI tool ppwizard commands would be handled better. 

 Example 

 In the following example "HTML[]" was used for a template: 

      

      

12345 ═══ 5.30. /Hook ═══ Switch /Hook[:When[;RexxFile]] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch allows you to call external Rexx code to perform processing at specific times. On success all hooks return a string which begins with "OK:", otherwise ppwizard treats the return code as an error and aborts processing. Some hooks allow you to pass information back to ppwizard (for example warning hooks can return "OK:IGNORE"). The rexx code for all hook types always gets passed these parameters: 1. Interface Version Number I will modify this value if you need to do anything to get your hook code running again. I recommend you check this value! 2. Source Location This value will contain the current location in the source that you are processing or "" if not processing any input file. It is intended for display purposes only, do not assume any specific format as it may change in the future. 3. When Code The reason this hook was called (as described below). If you wish, the same rexx code can be called for all hooks you process. In any case I recommend that the value be validated in case someone uses it incorrectly. If no parameter is supplied on the "/HOOK" switch then all hooks are turned off, otherwise the parameter is broken up into 2 components as follows: 1. When Code This parameter if empty indicates that all hooks are being adjusted, otherwise lists the hooks (seperated by ",") as follows:  GETFILELIST This hook allows you to create your own mask handler, this lets you determine what the mask means, for example you may only wish to process files that match the mask and were modified today. Extra parameters are: a. File Mask Location This is any drive or path component of the file mask. b. File Mask Name This is the file mask less any drive or path component. Combining this with the location will rebuild the original mask. c. Scan Subdirectories Either 'Y' or 'N', did user preceed filemask with '+'? You can ignore this if you wish, after all you have full control in how you evaluate the filemask. d. Output File This is the name of the output file into which you are expected to place the full names of files to be processed (one per line). Blank lines are ignored but all other lines are not and leading and trailing whitespace is not removed.  BEFORE This hook is called just before a build is started. Extra parameters are: a. PPWH_INPUT Contains "" or the full name of the base input file. b. PPWH_OUTPUT Contains "" or the name of the base output file. c. PPWH_TEMPLATE Contains "" or the name of any template file being used.  AFTER This hook is called after a build completes. Extra parameters are: a. PPWH_INPUT Contains "" or the full name of the base input file. b. PPWH_OUTPUT Contains "" or the name of the base output file. c. PPWH_TEMPLATE Contains "" or the name of any template file being used.  WARNING This hook is called for each warning that is not being ignored. Extra parameters are: a. PPWH_INPUT Contains "" or the full name of the base input file. b. PPWH_OUTPUT Contains "" or the name of the base output file. c. PPWH_TEMPLATE Contains "" or the name of any template file being used. d. Warning Message Text This contains the text of the message. If you wish to cause ppwizard to completely ignore the warning then you should return "OK:IGNORE". To ignore a message but still increment the warning counter then return "OK:IGNORE+".  ERROR This hook is called when an error occurs. Extra parameters are: a. PPWH_INPUT Contains "" or the full name of the base input file. b. PPWH_OUTPUT Contains "" or the name of the base output file. c. PPWH_TEMPLATE Contains "" or the name of any template file being used. d. Number of lines This contains the number of lines, each one is in it's own environment variable. Each line can be found in the PPWH_ERROR? environment variable (where '?' is the line number). Do not return anything but "OK:" otherwise you won't get the "see" the original error text. Note that you can specify any abbreviation of the above on the /hook switch, so for example "a" is the same as "after". 2. RexxFile This is the name of the rexx program that will be called to handle the hooks you have indicated. If not supplied then the hooks indicated are turned off. Example Switches REM *** CALL SAME HOOK for before, after and warnings *** /Hook:after,before,warning;hook.cmd REM *** CALL MULTI HOOKS for before, after and warnings *** /Hook:before;hookb.cmd /Hook:after;hooka.cmd /Hook:warning;hookw.cmd REM *** Reset some hooks *** /Hook:bef,a REM *** Reset all hooks *** /Hook Example - File Mask Handler The example shows how "dir" could be used, unix people could use either "ls" or "find" with appropriate switches to generate a list of files. In any case the processing can be as complex or as simple as you wish. /*--------------------------------------------------------------------------- ; MODULE NAME: LISTFILE.CMD ; ; $Author: USER "Dennis" $ ; $Revision: 1.0 $ ; $Date: 30 Mar 2001 18:05:30 $ ; $Logfile: C:/DBAREIS/Projects.PVCS/MultiOs/PPWIZARD/listfile.cmd.pvcs $ ; ; DESCRIPTION: Simple hook file to demonstrate for a "GETFILELIST" ; hook works. ; ; Hook code would generally tend to be operating system ; specific. This code was tested under OS/2 and would ; probably require MINOR changes to work elsewhere. ;----------------------------------------------------------------------------*/ /*--- I highly recommend use of trap handlers for ALL rexx code -------------*/ signal on NOVALUE name RexxTrapUninitializedVariable; signal on SYNTAX name RexxTrapSyntaxError; /*--- Get parameters --------------------------------------------------------*/ InterfaceVersion = arg(1); InterfaceType = arg(3); FileMaskLocn = arg(4); FileMaskName = arg(5); ScanSubdirectories = arg(6); /* You can ignore if you wish (you might have your own way of flagging it) */ OutputFile = arg(7); /*--- Get shortname of this routine -----------------------------------------*/ parse source . . RexxId; S1Pos = lastpos('/', RexxId); S2Pos = lastpos('\', RexxId); SlashPos = max(S1Pos, S2Pos); if SlashPos <> 0 then RexxId = substr(RexxId, SlashPos+1); /*--- Say what is going on --------------------------------------------------*/ if GetEnv("PPWIZARD_DEBUG") = 'Y' then do /*--- Debug is on! -------------------------------------------------------*/ say ''; call SayIt 'arg(1) = Interface Version = "' || InterfaceVersion || '"'; call SayIt 'arg(2) = Mask Location = "' || FileMaskLocn || '"'; call SayIt 'arg(3) = Mask less Location = "' || FileMaskName || '"'; call SayIt 'arg(4) = Scan Subdirs = Y|N = "' || ScanSubdirectories || '"'; call SayIt 'arg(5) = Temp File to create = "' || OutputFile || '"'; end; /*--- This code only designed to handle a single interface! -----------------*/ ExpectedInterfaceVersion = '00.050'; if InterfaceVersion <> ExpectedInterfaceVersion then Die('Unsupported Interface of "' || InterfaceVersion || '", Expected "' || ExpectedInterfaceVersion || '"'); /*--- This code only designed to handle a single hook type! -----------------*/ ExpectedInterfaceType = 'GETFILELIST'; if InterfaceType <> ExpectedInterfaceType then Die('Unsupported Interface of "' || InterfaceType || '", Expected "' || ExpectedInterfaceType || '"'); /*--- Want to scan subdirectories as well? (you can ignore this flag) -------*/ if ScanSubdirectories = 'Y' then Subdir = ' /S' else Subdir = '' /*--- Get a list using "dir" (could be "ls" or "find" in unix) --------------*/ Executing = '@dir "' || FileMaskLocn || FileMaskName || '" /F' || Subdir || ' > ' || OutputFile; if GetEnv("PPWIZARD_DEBUG") = 'Y' then call SayIt 'Executing: ' || Executing; Executing; /*--- Did the 'dir' command fail --------------------------------------------*/ if Rc <> 0 then Die('"dir" returned a return code of ' || Rc); /*--- All OK ----------------------------------------------------------------*/ exit('OK:'); /*===========================================================================*/ SayIt: /*===========================================================================*/ say RexxId || ' : ' || arg(1); return; /*===========================================================================*/ GetEnv: /* OS/2 specific function */ /*===========================================================================*/ return( value(arg(1),,'OS2ENVIRONMENT') ); /*===========================================================================*/ Die: /*===========================================================================*/ /*--- Return with error --------------------------------------------------*/ ErrorLine = SIGL; call SayIt 'ERROR(Line ' || ErrorLine || ') - ' || arg(1); exit(arg(1)); /*===========================================================================*/ CommonTrapHandler: /* */ /* arg(1) = Failing Line */ /* arg(2) = Type of trap (heading to be underlined) */ /* arg(3) = Trap specific Title (text description) */ /* arg(4) = Trap specific Text */ /*===========================================================================*/ /*--- Work out some details based on passed info -------------------------*/ FailingLine = arg(1); TrapHeading = 'BUG: ' || arg(2); TextDescription = arg(3); Text = arg(4); /*--- Work out name of THIS rexx procedure -------------------------------*/ parse source . . SourceFileName; /*--- Display details of the failing rexx code ---------------------------*/ say ''; call SayIt copies('=+', 39); call SayIt TrapHeading; call SayIt copies('~', length(TrapHeading)); call SayIt substr(TextDescription, 1 , 16) || ': ' || Text; call SayIt 'Failing Module : ' || SourceFileName; call SayIt 'Failing Line # : ' || FailingLine; call SayIt 'Failing Command : ' || strip(SourceLine(FailingLine)); call SayIt copies('=+', 39); /*--- We won't let a failure in one subprocedure stop others working -----*/ exit(TrapHeading || ' on line ' || FailingLine || ', ' || TextDescription || ': ' || Text); /*===========================================================================*/ RexxTrapUninitializedVariable: /*===========================================================================*/ /*--- Process the trap (it never returns) --------------------------------*/ ReginaBug = SIGL; call CommonTrapHandler ReginaBug, 'NoValue Abort!', 'Unknown Variable', condition('D'); /*===========================================================================*/ RexxTrapSyntaxError: /*===========================================================================*/ /*--- Process the trap (it never returns) --------------------------------*/ ReginaBug = SIGL; call CommonTrapHandler ReginaBug, 'Syntax Error!', 'Reason', errortext(Rc); Example HOOK file [HOOK.CMD] This example shows how one rexx procedure can handle many hook types (as well as how to write a number of different hook types). /*--------------------------------------------------------------------------- ; MODULE NAME: HOOK.CMD ; ; $Author: USER "Dennis" $ ; $Revision: 1.0 $ ; $Date: 30 Mar 2001 18:05:28 $ ; $Logfile: C:/DBAREIS/Projects.PVCS/MultiOs/PPWIZARD/hook.cmd.pvcs $ ; ; DESCRIPTION: Simple example hook file. ; ; ; NOTE: This is an example skeleton only ; ; There is no requirement that all hooks use the same ; rexx procedure, they can each use their own if you ; wish. ; ; Trap Handlers are very simplistic ; ; Do not assume specific format for location = arg(2) ; ; filespec() is only available on OS/2! That is MINOR ; changes will be required to run on other operating ; systems. ;----------------------------------------------------------------------------*/ /*--- I highly recommend use of trap handlers for ALL rexx code -------------*/ signal on NOVALUE name RexxTrapUninitializedVariable; signal on SYNTAX name RexxTrapSyntaxError; /*--- Get parameters --------------------------------------------------------*/ InterfaceVersion = arg(1); /* Both ends must know exactly how things passed! */ Location = arg(2); /* Location in source file */ HookType = arg(3); /* What hook type do we want processed? */ InputFile = arg(4); OutputFile = arg(5); TemplateFile = arg(6); WarningText = arg(7); ErrorLineCount = arg(7); /*--- Get shortname of this routine -----------------------------------------*/ parse source . . RexxId; S1Pos = lastpos('/', RexxId); S2Pos = lastpos('\', RexxId); SlashPos = max(S1Pos, S2Pos); if SlashPos <> 0 then RexxId = substr(RexxId, SlashPos+1); /*--- Display "parameters" (if user has debug mode on) ----------------------*/ if GetEnv("PPWIZARD_DEBUG") = 'Y' then do /*--- Debug mode is on ---------------------------------------------------*/ call SayIt 'Hook Type = "' || HookType || '"'; if Location <> '' then call SayIt 'Source Locn = "' || Location || '"'; call SayIt 'InputFile = "' || InputFile || '"'; call SayIt 'TemplateFile = "' || TemplateFile || '"'; call SayIt 'OutputFile = "' || OutputFile || '"'; end; /*--- Lets set up default OK parm (return code) -----------------------------*/ OkParm = ''; /*--- Do hook specific processing -------------------------------------------*/ select /*++++++++++++++++++++++++++++++++*/ when HookType = "WARNING" then /*++++++++++++++++++++++++++++++++*/ do /*--- Display if in debug mode ---------------------------------------*/ if GetEnv("PPWIZARD_DEBUG") = 'Y' then call SayIt 'WARNING = "' || WarningText || '"'; /*--- Log to file ----------------------------------------------------*/ /*--- Tell caller to ignore ------------------------------------------*/ OkParm = "IGNORE"; end; /*++++++++++++++++++++++++++++++++*/ when HookType = "ERROR" then /*++++++++++++++++++++++++++++++++*/ do /*--- Display if in debug mode ---------------------------------------*/ if GetEnv("PPWIZARD_DEBUG") = 'Y' then do /*--- Display Each line ------------------------------------------*/ do Line = 1 to ErrorLineCount call SayIt 'ERROR TEXT = "' || GetEnv("PPWH_ERROR" || Line) || '"'; end; end; /*--- Log to file ----------------------------------------------------*/ end; /*++++++++++++++++++++++++++++++++*/ otherwise /*++++++++++++++++++++++++++++++++*/ nop; end; /*--- Say OK ----------------------------------------------------------------*/ exit("OK:" || OkParm); /*===========================================================================*/ SayIt: /*===========================================================================*/ say RexxId || ' : ' || arg(1); return; /*===========================================================================*/ GetEnv: /* */ /* arg(1) : Name of environment variable. */ /*===========================================================================*/ return( value(arg(1),,'OS2ENVIRONMENT') ); /*===========================================================================*/ CommonTrapHandler: /* */ /* arg(1) = Failing Line */ /* arg(2) = Type of trap (heading to be underlined) */ /* arg(3) = Trap specific Title (text description) */ /* arg(4) = Trap specific Text */ /*===========================================================================*/ /*--- Work out some details based on passed info -------------------------*/ FailingLine = arg(1); TrapHeading = 'BUG: ' || arg(2); TextDescription = arg(3); Text = arg(4); /*--- Work out name of THIS rexx procedure -------------------------------*/ parse source . . SourceFileName; /*--- Display details of the failing rexx code ---------------------------*/ say ''; call SayIt copies('=+', 39); call SayIt TrapHeading; call SayIt copies('~', length(TrapHeading)); call SayIt substr(TextDescription, 1 , 16) || ': ' || Text; call SayIt 'Failing Module : ' || SourceFileName; call SayIt 'Failing Line # : ' || FailingLine; call SayIt 'Failing Command : ' || strip(SourceLine(FailingLine)); call SayIt copies('=+', 39); /*--- We won't let a failure in one subprocedure stop others working -----*/ exit(TrapHeading || ' on line ' || FailingLine || ', ' || TextDescription || ': ' || Text); /*===========================================================================*/ RexxTrapUninitializedVariable: /*===========================================================================*/ /*--- Process the trap (it never returns) --------------------------------*/ ReginaBug = SIGL; call CommonTrapHandler ReginaBug, 'NoValue Abort!', 'Unknown Variable', condition('D'); /*===========================================================================*/ RexxTrapSyntaxError: /*===========================================================================*/ /*--- Process the trap (it never returns) --------------------------------*/ ReginaBug = SIGL; call CommonTrapHandler ReginaBug, 'Syntax Error!', 'Reason', errortext(Rc); ═══ 5.31. /HTML ═══ Switch /HTML This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch should rarely be required as html mode is the default mode unless all input files end in the extension ".X" (its use is recommended for rexx source code). On non unix operating systems lines end with carriage return followed by linefeed, with the internet unix has finally won (it only requires lines to terminate with a linefeed). Web servers and browsers do not require the carriage return (which they ignore). You can save an extra one character per line with use of the /CRLF switch. This switch can be used any number of times and will affect all input masks that follow. It also becomes the default mode for all files produced via the #Output command. For backwards compatability, if an input mask is found before any processing mode switch then the last instance of a processing mode switch is used these. ═══ 5.32. /HtmlGenerator ═══ Switch /HtmlGenerator:Contents This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. By default when generating HTML, ppwizard will try to insert a meta tag similar to the following in the "HEAD" section: You can turn off the generation of the tags altogether by specifying an empty value or you can supply alternative line(s). PPWIZARD is supplied as freeware and I would appreciate it if you at least mention PPWIZARD and its homepage in the pages that you generate (either in meta tags or comments). The switch is mainly supplied so that you can add your own details if you wish. If you wish to specify your own generator contents (or refer to ppwizard details in HTML comments) you can make use of these variables (on the command line replace '<' with '{x3C}' and '>' with '{x3E}') : 1. 2. 3. 4. The value you wish to give this switch is probably so large that you would normally need to use the /GetEnv switch to get the information out of an environment variable. ═══ 5.33. /Inc2Cache ═══ Switch /Inc2Cache[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch can be used to override the way PPWIZARD includes files. This would not normally be required as PPWIZARD is likely to choose a good way. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO Warning Loading the files to cache will of course require more memory than you'd otherwise require. ═══ 5.34. /IncludePath ═══ Switch /IncludePath[:PathList] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. When ppwizard looks for a file (such as when it encounters a #include command) it searches in certain locations. This switch allows you to specify your own locations which will be searched before ppwizard looks in the standard ones. If you don't supply a parameter ppwizard will forget (drop) any locations you have previously specified otherwise you are supplying a a list of items separated by ";" (or colon for unix). If the item begins with a "*" character then what follows is the name of an environment variable whose contents should be searched otherwise it specifies a directory. It is a common requirement that the current directory be searched first if you need this to be searched before your supplied paths then you need to tell ppwizard this! Example ppwizard.rex 1.in /IncludePath /IncludePath:.;c:\second;c:\third /IncludePath:c:\fourth ═══ 5.35. /Info ═══ Switch /Info[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. By default important informational messages may be output, these could be considered as similar to a warning but not as severe. They inform you of situations that are unusual but may be perfectly OK in your environment. This switch allows you to turn these messages off. It is recommended that you do not turn them off. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.36. /List ═══ Switch /List[:ListFileName] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch allows you to pass a file containing a list of ppwizard switches and/or file masks (possibly produced by a /hook hook) to ppwizard. Inline comments are removed (these begin with ';;'). Blank lines or lines beginning with ';' are ignored. Each line must contain one and only one file mask or ppwizard option. Leading and trailing spaces are removed all others are replaced with '{x20}' as it is assumed they are required. One of the advantages of using a list file to hold options is that you do not have any problems with the operating system's command line processing getting in the way, for example you can use redirection characters such as '>' without problems. Note that ppwizard will automatically read in any file named "ppwizard.ppw" (default project file) using this mechanism. This makes it much simpler to use ppwizard via a graphical interface (such as Window's explorer) while also making it easier to use from the command line. Te list file can of course load other definitions from environment variables or other list or project files if required. The main difference between the "/list" switch and using "@" to indicate a project file is that with the "/list" switch you specify where the file is and with project commands such as "@all" ppwizard will look for a file called "all.ppw" in certain locations (current and ppwizard directories). Example Of LIST File ;----------------------------------------------------------------------- ;--- This file builds HTML for all "*.IT" files in current directory --- ;----------------------------------------------------------------------- *.IT ;;Only build files matching this mask /DependsOn:DEP\*.DEP ;;Only rebuild files that need it (new or modified) /Output:OUT\*.htm ;;I like files generated into the "out" directory and with the ".htm" extn ═══ 5.37. /Making ═══ Switch /Making:MakingTextSpec This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. When PPWIZARD is making a file it normally displays text similar to "Making - this.htm", this switch allows you to modify what is displayed. You can specify text for each of the possible processing modes (COPY, HTML, OTHER and REXX). The "MakingTextSpec" parameter is of the format "/Mode/Text" (the text if blank reverts to default). The Text may contain the following special text:  {ID} - Input file directory  {IS} - Short input filename  {IL} - Long input filename (absolute)  {OD} - Output file directory  {OS} - Short output filename  {OL} - Long output filename (may be relative)  {PM} - Processing Mode Example The following sets up the "making" text for the rexx processing mode. ppwizard /making:/REXX/We{x20}are{x20}making{x20}REXX{x20}CODE{x20}-{x20}{OL} This is doing exactly the same thing: ppwizard ~/making:/REXX/We are making REXX CODE - {OL}~ ═══ 5.38. /OnERROR ═══ Switch /OnERROR[:FailedCommandLine] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. The "FailedCommandLine" if non-blank specifies the command line of a command which is to be executed if ppwizard fails for any reason. A typical use for this would be to display the output in a viewer or editor. This could be very handy if you wish to work in a GUI (graphical) environment such as Windows Explorer or the OS/2 WPS. The /OnOk switch is closely related to this one. Some Command Parameters The command may contain the following strings:  {ConsoleFile} The name of any console file or "". A console file can be specified with the /ConsoleFile switch.  {ErrorFile} The name of any error file or "". An error file can be specified with the /ErrorFile switch. Example set ppwizard_errorfile=out\1.$$E set ppwizard_consolefile=+out\1.$$C regina out\ppwizard.rex 1.in /OnOK:notepad{x20}{ConsoleFile} /OnERROR:notepad{x20}{ErrorFile} /output:out\1.htm /debug >nul 2>&1 ═══ 5.39. /OnOK ═══ Switch /OnOK[:OkCommandLine] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. The "OkCommandLine" if non-blank specifies the command line of a command which is to be executed if ppwizard successfully completes. A typical use for this would be to display the output in a viewer or editor. This could be very handy if you wish to work in a GUI (graphical) environment such as Windows Explorer or the OS/2 WPS. See the /OnError switch for an example and more information about some parameters you can use. ═══ 5.40. /Other ═══ Switch /Other This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch indicates that the input is not one of the types specifically supported such as HTML or REXX. It turns of any funny stuff while in #AsIs Mode. This switch can be used any number of times and will affect all input masks that follow. It also becomes the default mode for all files produced via the #Output command. For backwards compatability, if an input mask is found before any processing mode switch then the last instance of a processing mode switch is used these. ═══ 5.41. /Option ═══ Switch /Option:OptionParameters This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. The "OptionParameters" is basically anything that is acceptable on the #option command. When PPWIZARD starts it sets up a default value for each option. This switch allows you to modify the value to suit your needs. Warning You may need to be careful about some of the characters used on a command line or when setting an environment variable. For example from an OS/2 command prompt you can not set an environment variable to a value that contains an equal sign, you would need to use '{x3D}' (it's ASCII code in hexadecimal) instead. Example The following is an extract from a much larger batch file I use: set DEBUG=/debug /option:debuglevel=/-all/ regina.exe ppwizard.rex /option:Warnings="IPFO" PPWIZARD.D %DEBUG% /output:%MAKEHTML%\*.htm ═══ 5.42. /Output ═══ Switch /Output:EditMask This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This parameter controls how the "InputFile" parameter is transformed to generate the correct name for the generated output file. An edit mask is basically much like a file (with path if required) and will contain zero or one special characters as follows: 1. *.* or {$SHORT} This gets replaced with the short filename (no path) of the current input file. 2. * or {$BASE} This gets replaced with the short filename (less path and extension) of the current input file. 3. {$FULL} This gets replaced with the full filename (with path) of the current input file. 4. ? or {$PATH} This gets replaced with the path (including terminating slash) of the current input file. This is most likely to be of use if you want to position generated files relative to the input file and your mask scans subdirectories. For example "?OUT\*.HTM". 5. {$path} This allows you to set up a separate tree for generated filenames, the input mask and file are examined and the relative path extracted, the result is either blank ('') or a relative path that ends with a path separator. Note for this to work the input mask must either use an absolute path, begin with '.' or '..' followed by slash or not have a path attached at all otherwise ppwizard will abort. It would be pointless to use this sort of path unless subdirectories are being scanned. You may wish to investigate the /BaseDir switch. Note that unix type operating systems will probably have problems with "$path" etc (to unix this means replace with the "path" environment variable's contents). You need to hide or escape the dollar sign, so use either "{x24}path" or "\$path" instead. The "EditMask" can be absolute or relative (your exact circumstances will determine your choice). Note that resultant relative filenames are always relative to the current directory. While you control the case of the mask you can't control the case of the part that replaces the '*'. What you can do is ensure the whole name is either in upper or lower case with the /FileNames switch. The default mask is "*.htm". I place all my output into a separate "OUT" directory and use "/Output:OUT\*.htm" instead. This switch can be used any number of times and will affect all input masks that follow. For backwards compatability, if an input mask is found before this switch then the very last instance of this switch is used for these. ═══ 5.43. /OutHeader ═══ Switch /OutHeader:Spec This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. For some output extensions or file types PPWIZARD automatically outputs a header at the start of the file. You can turn this off, on, or tweek the output using this switch. The first and last characters of the "Spec" defines the delimiter being used to delimit the following values: 1. Extension The extension (without a dot) that you are modifying the header for. Specify this in UPPER case unless the case is significant (as it would be in Unix). You can also use "*" to apply this rule to all files that don't have a specific rule. 2. Start of Comment Block The line that begins the comments. 3. Start of Middle Lines The characters that begin a line between the start and end lines. 4. End of Comment Block The line that ends the comments. Note that if the last 3 values (start/middle/end) are empty or missing then the comment is turned off. If the start value starts with '@' and there is no middle or end then this indicates that a file should be read to create a header. The included header is basically just like any other included file but I recommend that its only task be to take care of the header. If your header file included conditional generation of the header based on the extension of the output file then it could make sense to use a "*" rule. This allows you to have full control over the contents of the header. Examples The following shows how header comments in files with the extension ".REX" can be turned off: /OutHeader:~/REX/~ The following shows how header comments in files with the extension ".VBS" can be specified: /OutHeader:~$VBS$'{x20}===============$'{x20}$'{x20}===============$~ The following shows how a file can be included to produce a custom header (it can perform any required commands): /OutHeader:~/VBS/@OutHeader.H/~ The following is an example of what the "OutHeader.H" file could look like: ;--- What is the extension of the output file ------------------------------- #NextId #DefineRexx '' ;---- Get extension (if not unix then make upper case) ------------------- @@Extn = _filespec('EXTN', ''); #if ['' <> 'UNIX'] @@Extn = translate(@@Extn); ;;Make upper case #endif ;---- Want a comment? --- @@Line = copies('+*', 30); select ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% when @@EXTN = "HTM" | @@EXTN = "HTML" then ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do ;--- HTML --- @@WantCmt = 'Y' @@Start = ''; @@Line = '' end; ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% when @@EXTN = "VBS" then ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do ;--- VB SCRIPT --- @@WantCmt = 'Y' @@Start = "'" || @@Line; @@End = @@Start; @@Line = "'" end; ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% when @@EXTN = "REX" | '' = 'REXX' then ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do ;--- REXX --- @@WantCmt = 'Y' @@Start = '/* ' || @@Line; @@End = ' * ' || @@Line || '*/'; @@Line = ' *' end; ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% otherwise ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@WantCmt = 'N' end #DefineRexx ;--- Exit if we don't want to generate a output header for this EXTN --- #if [@@WantCmt = 'N'] #eof 1 #endif ;--- Generate the output comment --- Generator : PPWIZARD version under : FREE tool for Windows, OS/2, DOS and UNIX by () : Time : Input File : Output File : ═══ 5.44. /Pack ═══ Switch /Pack[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch is only useful if "/rexx" is also specified. You can get a much smaller generated rexx program by packing (off by default). Packing does not significantly slow down processing. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO MORE ON PACKING The preprocessor packs well written code (by my definition!) and can fail to correctly pack code where strings are appended without the use of the "||" operator (as the excess spaces will be removed). For example the following statement will not create the string you expect when packed: BothPartsCombined = 'Value:' TheValue; The following statement is a version of the above that will work: BothPartsCombined = 'Value: ' || TheValue; You can get very good results by packing but if you have got legacy code or you don't wish to change (your evil ways!) you should use the "/Pack:N" command line switch. This turns off most packing (rexx comment and trailing ';' removal still occurs). If you have trouble with some parts of your code but the bulk packs well then you may wish to consider leaving packing on and using the AllowPack option to indicate parts of your rexx code that should not be packed. WARNING This has not been tested on object rexx so I don't know if it will work or not (I assume it will). ═══ 5.45. /Rexx ═══ Switch /Rexx This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. The input is treated as rexx source. Rexx comments are removed from the source. This switch can be used any number of times and will affect all input masks that follow. It also becomes the default mode for all files produced via the #Output command. For backwards compatability, if an input mask is found before any processing mode switch then the last instance of a processing mode switch is used these. Packing of the resultant rexx code (within one generated line) occurs by default. You can specify "/Pack" if you don't want this done. Turning off packing will speed up the generation of rexx code but in my mind the compression gain from leaving it on is worth it. Other options you may wish to use are "LeaveBlankLines" & "KeepIndent". WARNING Note that if you are taking unknown code and passing it through the preprocessor to reduce its size you should use the "/Pack;N" option as there are situations where the operation of the code will be affected. Some good and safe reduction in code size will still occur. ═══ 5.46. /RegSyntax ═══ Switch /RegSyntax This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch only has affect when generating rexx code under OS/2. PPWIZARD always checks the generated code by asking the interpreter you are using to validate it. The OS/2 classic (not sure about OO) rexx interpreter does not do as good a job as regina in detecting syntax errors. By default ppwizard will use the OS/2 version of regina to perform a second syntax check assuming that the first (done by OS/2's rexx) passed it. PPWIZARD will look for a file called "ROS2REXX.EXE" in the same directory as PPWIZARD as well as in the PATH. This switch allows you to either turn off the checking altogether (pass '-') or specify the full name of the rexx interpreter. ═══ 5.47. /RedirMethod ═══ Switch /RedirMethod:Method This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This option can be used in the very rare situation that ppwizard does not use the correct format for redirection of standard out and error. This is likely to only occur on unix operating systems. The method should contain one of the following values:  @bash Redirection is performed as per Windows NT, OS/2 and most unix shells, that is: Command > File 2>&1  @csh Redirection is perform as per 'C' shell and some versions of the bash shell, that is: Command >& File  Anything Else Redirection is performed EXACTLY to your specification, this is a catch all that probably won't be used. If you do need it please contact me at "dbareis@labyrinth.net.au" and I will give it a name and document it. Basically you supply the string of characters required and any place where you want the filename replaced you use "{?}". ═══ 5.48. /SpellAddWord ═══ Switch /SpellAddWord:[-]NameOfAddFile This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This option can be specified if you have used /SpellCheck (use empty dictionary if required) to enable spell checking. What it allows you to do is indicate which incorrect words should be added to a dictionary file. All words you wish to add are added to the file sorted in order of the number of occurances of this word so that the most frequently used (therefore most important) are first. You would typically manually cut and paste words from the generated file to one of your dictionary files. To automatically add all words to the file preceed the filename with "-". ═══ 5.49. /SpellCheck ═══ Switch /SpellCheck:NameOfDictionary This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This option loads a dictionary and turns on spell checking. The switch can be used any number of times to load as many dictionaries as you wish. As an example you might wish to set up "GLOBAL.DIC", "PROJECT.DIC" and "JUNK.DIC". You may need to set up "JUNK.DIC" to hold junk words that are not really valid but get picked up as words during the spell check. In interactive spell checking such as in Microsoft word, these junk words are the annoying ones you keep replying "Ignore All" to! Note that ppwizard ignores the case of words and should work for international languages such as German. The /SpellAddWord will help you update or create dictionaries. A dictionary file must exist and it can be empty. There are large dictionaries available (such as in isspell40.zip on hobbes) however this take too long to load if you are impatient like me. The extra time will be required to load the extra words into memory, once loaded I do not think it will take longer to process your files. Spell checking has 2 basic modes (you can use both together) as follows:,  You can indicate words that you frequently get wrong and ppwizard will tell you when you use the word.  You can supply a list of "good" words (dictionaries) and ppwizard will tell you if you use a word which is not in a dictionary. Dictionaries All leading whitespace on all lines is ignored as are any blank lines or lines that begin with ';' (a comment). There are two types of dictionary entries as follows: 1. A valid word. Each word occurs on its own line. The fact that we have loaded at least one dictionary word (you are not required to do so) means that ppwizard will try to validate (spell check) all words. Note that a "word" can contain any characters and so if required could be "ASD%^". 2. A '$command' as follows:  $MISTAKE This command allows you to specify a word that you frequently get wrong. Ppwizard will tell you if you use this word. The command takes one or two parameters the first parameter is the incorrectly spelt word while the second (if passed) is the word correctly spelt.  $DELIMITERS If you don't like the default delimiters that ppwizard uses then you can specify a rexx expression which represents the delimiters you wish to use. Each character you specify is converted to a space and is therefore ignored. A warning is generated if this command is used more than once. Example of Dictionary ;--- Add common mistakes ---- $mistake seperate ;--- Specify alternate delimiters ---- $Delimiters d2c(9) || ',.=:;<>&-%()!/~?#${}[]"' ;--- A few words ---- THE CAT DOG computer. ═══ 5.50. /SpellShowAll ═══ Switch /SpellShowAll[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. By default you only see a warning for the first time a word error occurs in each build. This switch allows you to indicate that you would like to see every error. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.51. /Sleep ═══ Switch /Sleep:SecondsOk[,SecondsError] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This option can be used to pause execution for a period of time after PPWIZARD completes processing normally (OK) or abnormally (ERROR). Used with the "/DependsOn" switch in a simple batch file could be used in place of a CRON step to poll for data file changes. If you like the sound of this be sure to also check out the "/Template" switch. By default there is a small delay on error to allow you to see the error in case the ppwizard command is in a larger batch file etc. This delay is removed if /OnError is used (unless this "/sleep" switch has been used). ═══ 5.52. /Template ═══ Switch /Template:TemplateFile This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. Normally PPWIZARD begins by reading from the input file. This switch modifies this behavior. If you have a set of pages which look alike you can set up a single template file which describes the common attributes (header/footer, look and feel, background colors etc) and many "data" files each of which describes the differences (such as the title and page text). When this switch is used the name of the "data" file is stored in the variable "" and the file named on this switch is loaded instead. The template does not automatically load or know of the data file, it is up to you to perform the appropriate action which would usually be to simply include the "data" file using:  #include  #import Example A typical template file might begin like: ;--- Load data file, this template specified on "/template" switch --- #include "" ═══ 5.53. /UNC ═══ Switch /UNC[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. PPWIZARD includes some code which is only in place to cover common user errors, this code reduces double path slashes to single. If you use UNC names this will interfere with them. This option allows you to turn off the slash reduction (by passing "Y"). If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.54. /Validate ═══ Switch /Validate:[{RcTest}][!]Command This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch allows you to specify a command which will be executed if the output file is successfully generated. This will frequently be a validation step but ppwizard does not care what you specify on the command line or it's purpose. Another common use would be to use ppwizard as a preprocessor step and then call the program which will use it's output directly. The "#OnExit #EXEC" command can be used to do the same thing from within a header file. The command may contain references to macros or standard definitions. The string "{?}" represents the output file. Normally the command output is hidden and captured if in debug mode. To see the output preceed the command with the '!' character. If "RcTest" is not supplied then the return code is ignored otherwise it is a rexx expression where the rexx variable "CmdRc" holds the commands return code. A boolean result is expected with TRUE meaning the validation was successful. Under Windows 95-ME you probably can't get any decent return codes at all (due to major bugs in it's command processor), but even on Windows NT or 2000 be aware that both within the operating system itself as well as in other 3rd party programs there are a lot of situations where return codes can't be trusted (must be the monkeys fault?). Examples ppwizard *.it /output:out\*.htm /validate:Doit.exe{x20}"{?}" ppwizard *.it /output:out\*.htm /validate:{CmdRc=0}MyValidate.exe{x20}/x{x20}"{?}" The following example shows ppwizard creating a temporary (or intermediate) file which is used by another program. PPWIZARD has been used to preprocess the file so the second program has the advantage of being able to make use of all ppwizard features such as file inclusion, macros and conditional generation: %COMSPEC% /c ppwizard.cmd os2setup.db /output:out\os2setup.tmp /validate:{CmdRc=0}wpsobj.exe{x20}MakeObjects{x20}out\os2setup.tmp /debug >out\OS2SETUP.LOG 2>&1 if not errorlevel 1 goto CreateOk echo *** echo *** Create of PPWIZARD objects has failed... echo *** Will display "out\OS2SETUP.LOG" (contains details). echo *** pause e.exe out\OS2SETUP.LOG goto EndBatch :CreateOk ═══ 5.55. /WarningsRc ═══ Switch /WarningsRc[:WantedRc] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. By default when one or more warnings are displayed a return code of 1 will be returned. You can use this switch to set any return code you like (the default is 1). When you supply a value of 0 it indicates that you don't care what warnings were displayed, you do not consider a warning to be an error. You can get more fine tuning with the Warnings option. ═══ 5.56. /XSlash ═══ Switch /XSlash[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. In any location where ppwizard needs to generate html tags you can control whether or not it generates the "" format suitable for XHTML etc when this is required. By default ppwizard does not generate the extra space followed by slash. The output of the "" macro is dependent on the XSLASH state. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.57. /**/ ═══ Switch /**/[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch only has affect when /rexx also used to turn on rexx processing. Normally rexx comments on ends of lines are removed. Use this switch to leave them in. Normally there would be no need to leave them in however you might choose to do so to aid runtime debugging. If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO ═══ 5.58. /#Include ═══ Switch /#INCLUDE:FileList] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch allows you to specify one or more files which should automatically be included before any other file processing takes place. To specify more than one they should be separated by a ';' character (or ':' under unix). You could use this if you supply a set of macros in header file and supply a batch file to run the preprocessor. You would then not have to require (or request) a user of your header to '#include' it themselves. Example ppwizard *.it /output:out\*.htm /CrLf /#Include:Header1.H;Header2.H ═══ 5.59. /$Trace ═══ Switch /$Trace[:YesOrNo] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. This switch sets the default "$trace" state for all #DefineRexx blocks. When $tracing is used rexx tracing code is inserted before most rexx lines (not statements). This inserted code will display the line of your code that is about to be executed and the current value of any variables that it references (also shows variables referenced by immediately previous statement). If the "YesOrNo" parameter is not specified then it defaults to "Y", otherwise one of the following values is expected:  Y  N  YES  NO PPWIZARD REXX TRACING Please be careful using this feature, a rexx command is generated to support the tracing so always use do/end blocks when tracing within true or false "if" blocks etc. To provide an example, the following code will fail!: if x = 1 then A = X; else A = 2; To be able to trace this code you will need to change it to: if x = 1 then do A = X; end; else do A = 2; end; The addition of tracing code is fairly primative, however the rule is basically simple, it must be valid and not break your code for a rexx statement to be inserted between any lines of your code. There are a few exceptions, ppwizard will not insert code before any lines that are known "dangerous" ones such as "then", "do" and "else". If you don't wish to follow the "rules" then do not use any "$trace" facility. You will probably get a rexx trap (unexpected "do" or similar) if a line is incorrect trapped but I'm not going to guarantee this... This type of tracing can be much easier to understand than normal rexx tracing and also allows you to specify breakpoints (see below). Also unlike OS/2 rexx tracing, Regina's tracing is almost useless. For these reasons and to reduce clutter it is suggested that the PPWIZARD macro "REXXTRACE" be set to "OFF". To make things easier to understand I'd suggest that you use /beep and /color to turn on beeping on error and color highlighting. SETTING BREAKPOINTS You can set a breakpoint so that tracing stops (you are given a rexx debug command prompt) when the trace output contains specified text. You must not be redirecting output when a breakpoint expires otherwise you will of course not be able see anything and ppwizard will be halted (waiting for your replies)! Before rexx code is executed ppwizard looks to see if the "REXX_BP" macro exists, if it does then this value is used as an initial breakpoint value. The value can be one of the following: 1. A value of "?" indicates that you wish to set a breakpoint that matches all traced lines. 2. A value of "=MacroName" indicates that you wish to call some rexx code you have defined. It could dump variables and/or indicate that you wish to stop (bring up a debug command prompt). Rexx variables that you may wish to use are:  rtStop Set this variable to "Y" to cause ppwizard to stop (breakpoint expires).  RtSearchText This variable contains the text that you can compare with to see if a breakpoint should expire. You are more likely to look at the variables directly yourself, if so then please be careful not to try to display variables that don't exist or your tracing code will trap (ppwizard will display the error and continue). You can use the rexx 'symbol()' routine to determine if a variable exists. 3. Any other value indicates that you wish to break on all lines that contain the text you provided (case sensitive). You probably determined a good value by looking at the rexx trace output from a previous run. Note that the string "{SOL}" represents the start of a line and "{EOL}" represents the end of a line. All leading and trailing spaces have been removed and there is never two or more spaces in a row. When a breakpoint expires the current line will be displayed, it will not have been executed and won't be until you press enter at the prompt. BREAKPOINT COMMAND PROMPT When a breakpoint expires you will be given a command prompt where you can type:  Empty Command If you don't enter any command (that is simply press [enter]), ppwizard continues until the breakpoint expires again.  ? In case you have forgotten the step you are up to or it scrolled off the screen then you can redisplay just the text of the message again (no variables are dumped).  ?a[liases] This command shows you all aliases that you have created in the past.  ?#[aliases] All commands that you type in are automatically remembered. This command is used to list the commands, to reuse a remembered command you need to specify it by number (which changes as you enter new commands - but not as you use previous ones).  ?v[ariables] This dumps all known variables, for the entire user script. Note that this won't dump whole arrays, just variables that are easily recognisable by looking at the rexx code.  /alias This executes a previously set up command. It's a shorthand way of specifying frequently used commands. If the alias is numeric or begins with '#' then this is referring to an automatic alias and not one that you created.  /alias=value This allows you to specify a command. Do not use an alias that begins with '#' or is numeric.  BP This will prompt you for a new breakpoint. Type "" for none.  None of the Above You have supplied a rexx command which will be executed. If the command is "exit" then ppwizard will terminate! PPWIZARD protects you from syntax errors in this prompt. You could use this prompt to "say" the values of rexx variables or anything else you require (run programs or anything else you can normally do in a rexx program). Example of use is: ;--- Define some code that can be called to detect a breakpoint ------- #DefineRexx TestBreakpointCode "$TRACE_OFF" ;--- Simple test (same as simpler REXX_BP value) ---------- if pos('{SOL}x = 2{EOL}', RtSearchText) <> 0 then rtStop = 'Y'; ;;Want debug prompt! ;--- Also stop if variable 'FRED' exists and equals '1' --- if symbol('FRED') = 'VAR' then do if Fred = 1 then rtStop = 'Y'; ;;Want debug prompt! end; #DefineRexx ;--- Other possible settings for below -------------------------------------- ;#define REXX_BP {SOL}x = 2{EOL} ;;Set break point for when x = 2 (whole line ie not "x=22" etc) ;#define REXX_BP =TestBreakpointCode ;;Stop where my code says ;#define REXX_BP_ALIAS ;project.a;global.a ;;Define alias files used (changes NOT saved) ;--- Define rexx code to be debugged (Execute it) --------------------- #define RexxTrace OFF ;;Don't want to see interpreters output #define REXX_BP ? ;;Stop anywhere (first $trace) #define REXX_BP_ALIAS project.a;global.a ;;Define alias files used (changes saved to "project.a") #DefineRexx '' Fred = 1; do x = 1 to 3 $trace ;;trace next command y = x; fred2 = Fred; end; ;--- Dump all vars now --- $trace Finished, dumping all vars #DefineRexx Some sample output (without breakpoint output): ---------- REXX TRACE - START(OFF) ---------- $TRACE: @4 -> y = x; fred2 = Fred | x = 1 | Fred = 1 $TRACE: @4 -> y = x; fred2 = Fred | y = 1 | x = 2 | fred2 = 1 | Fred = 1 $TRACE: @4 -> y = x; fred2 = Fred | y = 2 | x = 3 | fred2 = 1 | Fred = 1 $SAY: Finished,dumping all vars | Fred = 1 | x = 4 | y = 3 | fred2 = 1 ---------- REXX TRACE - END(OFF) ---------- COMMAND PROMPT ALIASES If ppwizard finds the "REXX_BP" macro then it also looks for the "REXX_BP_ALIAS" macro. The value of this macro is a list of alias files separated by semicolons. You as a user are allowed to create your own aliases from the command prompt, these are saved to the first file in the list, if you don't wish to allow saving then begin the list with a semicolon. All blank lines and lines that begin with ';' are ignored, otherwise the line contains a set alias command of the same format that you use on the command prompt, that is "/alias=value". Alias names can contain virtually any characters and if duplicated all but the first is ignored when read from a file. An alias specified on the command prompt overwrites any stored. If you do a lot of ppwizard rexx debugging you will probably want to set up at least project and global level aliases for frequently used commands. Note that there is no editing of alias commands at the command prompt, if you make a mistake you will need to either recreate the alias or modify the saved file when debugging complete. AUTOMATIC ALIASES These aliases are created automatically as you enter new commands. Only successful commands that did not trap are remembered. This facility allows you to refer to previously entered long commands with a short simple number. As you will see below it will also allow you to give "good" commands a decent name at the end of a debug session. As these aliases are also saved along with normal aliases you can edit the alias file after a debug session to give what you believe will be handly common commands "decent" names. When an alias file is read in the auto alias number is completely ignored so you don't have to worry about creating "holes" etc.

You can control how many commands ppwizard remembers with the "REXX_BP_MAX_AUTO_CMD" macro. This macro should specify the number of commands, if it contains an invalid value or does not exist it will default. ═══ 5.60. /@EXTN ═══ Switch /@EXTN[:ProjectFileMask] This is a PPWIZARD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable or in project files. After processing all other command line parameters (from all sources) ppwizard checks to see if all input files have the same extension, if so then it will also try to load a project file named "DEF_*.PPW" (the default mask), where the '*' represents the extension of the files. You can either turn off all extension based project handling by passing an empty value or change the name of the files. There is only one restriction, the project file can not try to specify more input files. ═══ 6. The Source Code ═══ The Source Code 1. There is no limit to how long a line may be, so the only practical limit will be whatever your editor or other tools impose. You will wish to also check out the following extra details:  White Space  Commenting  Line Continuation  Quoted Text - qTextq  Quoted Text - qRestq  Dependancies 2. There is a range of "Standard Definitions" available for use in your source. You can create your own as well (for example a formatted date/time of your document). 3. You can selectively include or exclude portions of the source code using the "#if" command. 4. Large portions of text (with or without HTML tagging) that you place in multiple places which you feel must be kept in sync can be defined once with "#define" and referenced many times. 5. If you wish to use PPWIZARD and a WYSIWYG (GUI) Editor and the editor cracks up at the PPWIZARD tags and commands you can used the /HideCmd switch to effectively hide ppwizard related stuff in html comments. ═══ 6.1. White Space ═══ White Space By default, leading whitespace is ignored. You can use the "KeepIndent" to alter this. Even when not ignored all PPWIZARD commands may be indented from the left if you wish. Trailing whitespace is always removed from a line. If you must have trailing whitespace you could specify one or more "" codes. By default blank lines (after comment removal) are ignored. You can use the "LeaveBlankLines" option to alter this. ═══ 6.2. Commenting ═══ Line Comments By default the commenting character is ';'. If a line begins with this character then it is ignored. If the line contains the character doubled up (as in ;;) then everything after the last occurance of this string is considered to be an inline comment and is removed. The line comment character can be modified with the LineComment option. You could add ';;' to the end of a line so that an earlier occurance and everything following does not get removed. You can also use the "" code if required. Note that if the line being dropped is in the middle of a set of continued lines then the line continuation characters at the end (or not at the end) of the dropped line are not ignored. Commenting Blocks of Lines The easiest way to comment out multiple lines at one time is to use the "#ifdef" command to check for a name that you will ensure never exists, such as in the following example: ;--- This is a line comment --- #define Highlight {$Text} ;;Comment here #ifdef xxxx 1st line commented out 2nd line commented out 3rd line commented out #endif ═══ 6.3. Line Continuation ═══ Line Continuation PPWIZARD can handle any length line (subject to any REXX interpreter limitations), however the editor you are using may have limitations or you just might want to format the line better. PPWIZARD allows you to specify that a line continues onto the next line. The two or more lines will be merged together. You can continue long lines by placing the line continuation characters (' \' by default) at the end of a line that continues onto the next. The #( command provides an alternative to the use of the line continuation characters and the #DefineRexx command provides a simpler way of formatting REXX code. It is not valid for the last line of a file to contain the line continuation characters, all combined lines must come from the one input file. This capability would be most useful for #define commands. The "LineContinuation" option can be used to disable line continuation or to change the continuation character. When you have a long #define statement that spans lines you can have any commands (such as #if, #elseif and #endif) within a continue block, however these commands themselves NEVER continue on following lines. While line continuation is taking place blank or comment lines are treated no differently from any other lines (that is they are not completely ignored as would normally be the case). If a comment line is found while collecting continued lines it must contain line continuation characters if the continuation is to continue. There are actually a number of line continuation types which make for an easier to read shorthand for other variations. All valid variations are listed below: 1. -\ All trailing whitespace is removed from this line before the next line is added. 2. +\ All trailing whitespace is removed from this line before a space and then the next line is added. 3. \ (space + slash) All trailing whitespace is removed from this line before a single space and the next line is added. 4. %\ All trailing whitespace is removed from this line before a newline code and the next line is added. If the line does not end in one of the above 2 character codes then the continuation character is ignored. Note that '+\' and ' \' currently serve the same purpose, in a future release you will probably be able to set the default continuation type for ' \'. Note that line continuation does not occur when the #AsIs "ON" is used. Example of #if Use Within Line Continuation #define TheSame \

Hi, my name is Dennis Bareis and I have \ been using OS/2 and developing for \ #if '<$AtWork>' = 'Y' \ ANZ \ #elseif \ *WRONG INC* \ #endif \ on and off since the original 1.0 version. The above shows the creation of a multi-line macro. It is recommended (and in some cases required) that the definition be formatted as above, that is the line is continued by '\' after the macro name. All other line continuation can be as per your requirements (the above is simple but not ideal...). Example - Good Formatting, Macro Use <$MyMacro \ Parm1=^a parameter^ \ Parm2=^a parameter^ \ Parm3=^a parameter^ \ > ═══ 6.4. Quoted Text - qTextq ═══ Quoted Text - qTextq Many commands require quoted text. The only thing special about the quotes in this program are that they can be almost any character (anything non-alphanumeric). Tthe only restrictions are as follows: 1. The same quote character must appear at the start and end of the text. 2. If another parameter follows then there must be at least one space after the end quote character. 3. You can omit the quote characters if the first character is alphanumeric and the the text does not contain spaces. The rexx function GetQuotedText() can be used in your own code to read quotes values such as this. EXAMPLES The following are examples of valid quoted strings:  "A string"  'Another string'  ^A 'string' which contains "quotes"^  █ABC█  NoQuotesRequired ═══ 6.5. Quoted Text - qRestq ═══ Quoted Text - qRestq Many commands require quoted text, this format of quoted text is only ever used for the last parameter of some commands. This is very similar in function to the "Quoted Text - qTextq" method except that no more parameters are expected after the current one. All "Quoted Text - qTextq" examples are valid. Everything is the same as for "Quoted Text - qTextq" except: 1. The quote character can actually appear within the quoted text. 2. If the value is unquoted the rest of the line (stripped of leading & trailing whitespace) is used. 3. Nothing follows the text. The rexx function GetQuotedRest() can be used in your own code to read quotes values such as this. EXAMPLES The following are examples of valid quoted strings:  ^A 'string' which contains "quotes"^  "A string with "imbedded" double quotes" ═══ 7. Macros ═══ Macros The "#include" command allows you to include external files (whole or selected fragments) so this would have to be the simplest and common way of obtaining code reuse and this is where facilities such as SSI (Server Side Includes) stop. PPWIZARD can do much more than this. Macros are collections of text and/or commands and would have to be one of the most important and most used features of this preprocessor. The most common ways of creating macros are with these methods: 1. #define[+] 2. #evaluate[+] 3. /define The simplest types of macro simply allows you to define text which you will use over and over again. You will want to specify it in one place so that if it ever changes you won't need to hunt up all occurances. The following example shows an email address being defined (this would normally be done in a central place and be accessed with #include): #define MyEmailAddress dbareis@labyrinth.net.au Now that we have defined the email address (once as per example above), in all the html pages that required it we could refer to it like:

If you have any questions or suggestions for improvements please feel free to email me. There are also a number of "Standard Macros" which always exist, these allow you to easily obtain information about the current time or files being generated or included. All sorts of useful information is available in standard formats, if you don't like the format of a particular item such as the "compile time" then it is a simple matter to use ppwizard to create your own format. There are some specialised forms of standard variables as follows: 1. 2. All normal macros are replaced before standard macros. The "" form is never replaced until just before the line is to be written to the output file. A macro's name (or parameter) can be very long and can contain nearly any character (space and end of macro replacement character are the main exceptions). You will be told if a macro name is invalid when you try to define it. The maximum length of a macro will be approximately 100 characters in OS/2 rexx and unlimited with the regina interpreter. The name of a macro (and it's parameters) are normally case insensitive, however you can make them case sensitive by using the CsReplacement option. When this option is not used all macros and parameters are converted to upper case. You now know enough to get started with simple macros which when used along with the "#include" command are powerful facilities for reuse, not only can you reuse all or parts of a file but you can define extremely small items which are too small to put into files of their own (such as email or web addresses). I recommend that you go on and at least the simplest macros section of the doco. After becoming familiar with ppwizard and it's basic features I recommend that all of the advanced sections listed below be read, while it can be a hard slog, understanding these sections can greatly improve the quality of what you can do. Some more advanced topics follow: 1. Multi Line Macros 2. Macros With Mandatory Parameters 3. Macros With Optional Parameters 4. Macro Parameters without values 5. Positional Parameters (not named) Even more advanced topics: 1. Using Standard Definitions + Using REXX Logic 2. Multi Line Macros With Logic 3. Die When Unused Parms 4. Expand All Unused Parameters 5. Expand All Parameters As Rexx Code 6. Expand Macro Name 7. $$ Transformation Commands ═══ 7.1. Simplest Macros ═══ Simplest Macros The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. The simplest macros don't contain any logic (just text) and are used where there are many places where you wish the same information used. For example you might have an email address which you will refer to from 10 different HTML pages. If this email address changes you do not wish to look for and then change all of these occurrances. Not only would this be a real pain but you could miss one or get the new email address wrong on one (which you might never realise). You have probably got more than one macro you wish to define (others might be web addresses for external links), it is suggested that in general the best place to keep all of them is together in one place. You could add all the macro definitions in one place in a file you create called "MACROS.IH". For example the contents of this file might be: ;--- MY EMAIL Information --------------------------------------------------- #define MyEmailAddress db0@anz.com #define EmailMeGraphic ;--- Standard Graphics ------------------------------------------------------ #define ImgUpdated updated #define ImgNew new #define ImgBarbedWire

;--- External WEB Addresses ------------------------------------------------- #define HttpNetLabsMainPage www.netlabs.org #define HttpNetLabsGimpPage www.netlabs.org/gimp/ #define HttpOs2WarpGuruMainPage www.geocities.com/SiliconValley/Pines/7885/ #define HttpOs2WarpGuruApmPage <$HttpOs2WarpGuruMainPage>DownloadAPM2.html At or near the start of the source for the html page (lets call it "Intro.IT") you would add the following statement to load the macros: ;--- Load all required definitions ------------------------------------------ #include "MACROS.IH" Later on in "INTRO.IT" you could have the following:

If you have any questions or suggestions for improvements please feel free to email me. As you may guess from the above example to refer to the macro you place '<$' at the start and '>' at the end of the macro (variables) name. There is now only one place to change if your email address changes. Not only that but if you get the new address wrong it should be immediately apparent as it will be wrong in all locations! So not only have you simplified the process but you have probably improved the quality of your output as well! There are better ways to handle what was demonstrated above but hopefully the example was a simple enough starting point. If you are still confused I suggest that you read the e-Zine! articles written by Chris Wenham (the Senior Editor of OS/2 e-Zine! chris@os2ezine.com). ═══ 7.2. Multi Line Macros ═══ Multi Line Macros The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. Sometimes a macro contains quite a bit of text and to make it easier you might wish to spread the definition over a number of lines. This will also allow you to add comments and spacing to allow it to be easy to read. When PPWIZARD sees a multi line macro (formatted in a similar manner to the example below - break after macro name) it breaks it up into multiple lines so that any imbedded PPWIZARD commands will get executed. You need to be careful to correctly begin a multiline macro, the first line must be of the form: #define TheMacroName \ The following is an example of an invalid definition (as it does not ensure a space follows the "TheMacroName" parameter as is required by the #define command). : #define TheMacroName -\ Also check out the #( command as it is also very useful for creating multiline macros. To define blocks of rexx code use the #DefineRexx command. Note that for ppwizard commands (within a #define) to be executed when the macro is expanded the commands must be on their own line. ;--- Define the macro ------------------------------------- #define FeedBackParagraphs \ ;---- First paragraph ----------------------------- \

I have put a lot of work into this produce and \ believe it to be of a very high standard. I \ always appreciate feedback which indicates which \ features you use and like and which you don't \ like. \ \ ;---- Second paragraph ---------------------------- \

Please email me \ with tour comments. ;--- Use the macro ---------------------------------------- <$FeedBackParagraphs> Notice that the expanded "<$FeedBackParagraphs>" will refer to our previously defined "MyEmailAddress" macro. It is perfectly legal for a macro definition to refer to any number of other definitions. ═══ 7.3. Macros With Mandatory Parameters ═══ Macros With Mandatory Parameters The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. Back to my previously defined email macro, whenever I use it I still have to duplicate a lot of HTML tagging. What we could do is create an email macro which accepts the text or graphic that the user would click to email me, as below: #define EmailMeLink {$VISIBLE} The above macro accepts a single parameter which must be supplied when the macro is used. The parameter's name is "VISIBLE". The macro refers to a parameter by placing '{$' at the start and '}' at the end of the macro parameters name. To use this macro we could say:

If you have any questions or suggestions for improvements please feel free to <$EmailMeLink VISIBLE="email me">. Note that when you supply the value for a macros parameter you can use virtually any character as a quote not just single or double quotes, for example you could say:

If you have any questions or suggestions for improvements please feel free to <$EmailMeLink VISIBLE=@email me@>. ═══ 7.4. Macros With Optional Parameters ═══ Macros With Optional Parameters The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. Also note that you can create a macro which accepts optional parameters. The "VISIBLE" parameter we have been using up to now is manditory (required), if not supplied the preprocessor will inform you of this fact and stop. To make a parameter optional you assign at least the first occurance of the parameter a default value. You can give each occurance a default value (which may be different), and the last specified default value is remembered for subsequent occurances where a default value is required but not specified. For example to change the email macro to use my email address as the default but allow the specification of alternative addresses I could do the following: #define EmailMeLink {$VISIBLE} You could then say:

If you have any questions or suggestions for improvements please feel free to <$EmailMeLink VISIBLE=@email me@>, I have another <$EmailMeLink VISIBLE=@email address@ EMAIL=$db1@anz.com$> which you might like to try. Advanced Example This example is demonstrating a bit more than just optional parameters as it is a good example on how you can to some degree simulate rexx like arrays or stem variables: ;--- Define some constants (make names likely to be unique) --- #define OPENIT_OPENMODE_TEXT 'T' #define OPENIT_OPENMODE_BINARY 'B' ;--- Allow user to specify "short" open mode! ----------------- #define OpenIt \ Open({$File}, <$OPENIT_OPENMODE_{$Mode=^TEXT^}>) ;;Call to fictional open routine ;--- Test the macro ------------------------------------------- OpenRc = <$OpenIt File="tfile"> OpenRc = <$OpenIt File="bfile" MODE="BINARY"> What the above demonstrated was a simple way of defining long names for constants with liitle or no chance of clashing with other variable names (possibly outside your control) but allowing the user to specify shorter more friendly aliases ("BINARY" instead of "OPENIT_OPENMODE_BINARY"). ═══ 7.5. Macro Parameters without values ═══ Macro Parameters without values The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. A macro reference would normally specify values for all parameters it uses, however there are times when this is not required. PPWIZARD does not require you to set a value, if you don't supply one then the name of the parameter in upper case is used. The definition of the macro would supply a default value in case the parameter (keyword) was not used and would normally do some conditional generation (using #if etc). The following example shows a simple macro with very little validation that simply assumes if the "keyword" "start" was not supplied that the "end" condition is required: ;--- Define the macro --- #define StupidMacro \ #if '{$START=""}' = 'START' \ start stuff \ #elseif \ end stuff \ #endif ;--- Use the macro --- <$StupidMacro start> ;;Start stuff <$StupidMacro> ;;End ═══ 7.6. Positional Parameters (not named) ═══ Positional Parameters (not named) The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. In some cases (especially with simple one parameter macros) you may simply wish to supply a value without bothering to name it. For example one way to implement a HTML comment might be: ;--- Define a macro (takes a parameter called "Text") ---- #define COMMENT ;--- Use the above macro --- <$COMMENT Text="This will become a html comment"> As you can see from the above we had to use "Text=" even though that is all the parameter could be (at least correctly), lets do this again but this time using a positional parameter: ;--- Define a macro (takes a single positional parameter) ---- #define COMMENT ;--- Use the above macro --- <$COMMENT "This will become a html comment"> Now the rules are that positional parameters must start with a double quote (as demonstrated above), a single quote or an equal sign. If unquoted the value is assumed to be a Parameters without a value. The macro contents refers to the parameters as a '#' followed by a decimal number which indicates it's position (there can be any number of positional parameters). The reason for the equal sign is that it allows you to quote a string with any quote character (otherwise you wouldn't bother). As an example the above "COMMENT" macro could be called as follows: ;--- Use the above macro --- <$COMMENT "Using double quotes"> <$COMMENT 'Using single quotes'> <$COMMENT =@Using any quotes (can then include '" <-- single and double quotes)@> ═══ 7.7. Using Standard Definitions + Using REXX Logic ═══ Using Standard Definitions + Using REXX Logic The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. The following example uses the "#evaluate" command and the "Standard Definition" of "" as well as demonstrating the use of using rexx code to include logic. ;--- Capture some HTML information ------------------------------------------ #evaluate ShortNameHtml "_filespec('name', '')" #evaluate ShortNameHtmlLowerCase "ToLowerCase('<$ShortNameHtml>')" The above defined two macros, the first is the short name of the output file (no path or drive attached) and the second is the same short name but all lower case. A "Problem" Notice that the first parameter to the rexx translate function above is surrounded by single quotes, we could safely do this only because we know that a filename can't contain single quotes! You need to be careful with your use of quotes etc as the macro replacement simply places the correct text where requested. We could have used the PPWIZARD "MacroGet" function if we were not sure about the quote situation as demonstrated below: ;--- Capture some HTML information ------------------------------------------ #evaluate ShortNameHtmlLowerCase "ToLowerCase(MacroGet('ShortNameHtml'))" There is another (probably better way) of handling the quote 'problem' as in: ;--- Capture some HTML information ------------------------------------------ #evaluate ShortNameHtmlLowerCase "ToLowerCase('<$ShortNameHtml $$SQX2>')" ═══ 7.8. Multi Line Macros With Logic ═══ Multi Line Macros With Logic The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. In this example we add some conditional inclusion where the same macro can generate different text based on the environment or parameters that are passed to it. In the following macro the size of the image file is calculated unless a value was passed to it. You might create a macros as follows to display some photos in a table: ;--- Photo macro will either use passed size or work out correct size for you --- #define Photo \ #evaluate+ LocalFileName ^"..\graphics\{$Image}"^ \ #DependsOn INPUT "<$LocalFileName>" \ \ #if "{$Size=''}" <> "" \ #define+ TmpSize {$Size=''} ;;User supplied size \ #elseif \ #evaluate+ TmpSize ^GetImageHeightWidth("<$LocalFileName>")^ \ #endif \ \ \ {$Title}

\ ALT="{$Title}"> \ \ It is then a simple matter to create format and add new photos as follows (note that the image size is automatically calculated): ;--- Create table of photos --------------------------------------------

;--- Include all my photos ------------------------------------------ <$Photo Image="lazy.jpg" Title="Watching TV"> <$Photo Image="carback.jpg" Title="New Car (Back Left)">
Pictures
═══ 7.9. Die When Unused Parms ═══ Die When Unused Parms The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. While PPWIZARD does show unused parameters when in debug mode, this does not cause ppwizard to complain. This is because there are a number of situations (some coding style issues as well) where you can expect to find some parameters whose values were not expanded by a macro. While PPWIZARD does not know if unused parameters might indicate an error, you do, so you can tell ppwizard to die if a macro is passed parameters that it does not use. You may not always get this error, for example if a manditory parameter was mispelt it would fail because the parameter was missing but it does provide some helpful extra validation. Some common mistakes that could be detected by this validation include:  The extra parameters may have been passed because the wrong macro was accidently used.  An optional parameter was mispelt and therefore not used.  A macro was modified but not all references were updated. This validation may slow down processing slightly but is probably worth it anyway if others will be using your macros. You could compromise and limit the validation to externally known macros and keep "internal" ones unvalidated. The main situation where you are likely to get a false hit is where a parameter's value is only used as a default for another parameter. In cases like this you could use the parameter with the '$$IGNORE' command so as to expand to nothing but mark the parameter as used. Otherwise if you get a false hit remove the validation on those macros or alter your style. The "ParmVal" option influences the operation of this tag. Example ;--- Define a macro that takes no parameters --- #define EMAIL fred@home.com{$!} ;--- Correct Use (no parameters) --- VALUE: <$EMAIL> ;--- Incorrect Use (some parameters) --- VALUE: <$EMAIL X=1 Y=2 "3"> ═══ 7.10. Expand All Unused Parameters ═══ Expand All Unused Parameters The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. This option allows you to create a ppwizard macro for a html tag and process any parameters you wish while expanding any you don't specifically make use of. For example the following is a simplistic "IMG" tag front end: #define IMG {$ALT='{$FILE}'} Notice the "{$?}" tag above, it will expand all parameters used on a reference except "FILE" and "ALT". You can also use "{$?ResetUsed}" if you want to process all parameters (used or not). If there are specific parameters that you don't want included (as yet unused) then you should preceed this command with the parameter using '$$IGNORE'. If there were no parameters then nothing is expanded else a space preceeds the resultant parameter. There are actually 2 modes of replacement, the above shows one mode where no "$$" Commands were used, if they were used then the commands are applied to each unused parameter in turn. In general one of the $$ commands would be a "pass" command. Using the $$ commands gives you much more quoting flexability and gives you the option of not passing on the parameters, you may wish to simply memorise them for later use. To allow you to use it any number of times, this parameter does not mark all the parameters as used. It does however disable any {$!} validation for the macro. ═══ 7.11. Expand All Parameters As Rexx Code ═══ Expand All Parameters As Rexx Code The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. This section describes an advanced rarely used or required facility which allows you to write a macro that can take variable parameters with unknown names etc. This is useful in cases where the macro logic is very generic but can be applied for an unknown number of parameters or parameters whose names may change (as the name itself is significant for the generated code). The parameter information that is expanded by "{$??}" is in the form of rexx code initializing an array (stem). This means that you would normally require rexx code to process the information. The information generated is as follows (where '?' represents a number 1 to 'n'):  MP.?.MPNAME This holds the name of the parameter in the case the user supplied.  MP.?.MPVALUE This holds the value of the parameter.  MP.?.MPUSED This holds 'Y' or 'N' to indicate whether the parameter was used in the macro prior to expansion of this code.  MP.?.MPTYPE This holds 'V' (for value) or 'NV' (no value) to indicate whether or not the parameter had a value. Note that "MP.0" holds the value of 'n', that is the number of parameters stored. Any "$$" commands are unfortunately ignored, tell me if you have problems with this. To allow you to use it any number of times, this parameter does not mark all the parameters as used. It does however disable any {$!} validation for the macro. Example This example code shows how the parameter is used and what it expands to but does not show the generated array being used in any way. The source code: #define TestQmQm {$??} *** 0 PARMS ***** <$TestQmQm> *** SOME PARMS ***** <$TestQmQm "Parm1IsPositional 1" Parm2HasNoValue Parm3="Parm3Value"> Generates: *** 0 PARMS ***** MP.0 = 0 *** SOME PARMS ***** MP.1.MPNAME = '#1' MP.1.MPVALUE = 'Parm1IsPositional 1' MP.1.MPUSED = 'N' MP.1.MPTYPE = 'V' MP.2.MPNAME = 'Parm2HasNoValue' MP.2.MPVALUE = 'PARM2HASNOVALUE' MP.2.MPUSED = 'N' MP.2.MPTYPE = 'NV' MP.3.MPNAME = 'Parm3' MP.3.MPVALUE = 'Parm3Value' MP.3.MPUSED = 'N' MP.3.MPTYPE = 'V' MP.0 = 3 The "Row" macro in my "WISEINST.WIH" is built around this facility. ═══ 7.12. Expand Macro Name ═══ Expand Macro Name The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. This section describes an advanced rarely used or required facility which allows you to write a macro that can determine the name of the macro being expanded (in the exact case used). This value can be obtained by using "{$MACNAME}". One example of where this could be handy is if you are marking the start of some sort of block for which you need an ending marker. If you would also like this block to be able to contain the ending marker (for example in documentation you may be showing someone how to do something) then you will need to perform a case sensitive search for the end block marker. The "<$eExample>" macro/tag (used in some of my headers) is an example of this sort of situation. If you vary the case on the start of block macros and can determine this case you can create a end block marker from this value. Example Some test code follows: #define TestMacName {$?MacName} #define TestMacNameUpper {$?MacName $$UPPER} *** Macro name *** MacroName = "<$TestMacName>" MacroNAME = "<$TestMacNAME>" MACRONAME = "<$TestMacNameUpper>" ═══ 7.13. Macro Tranformations ═══ Macro Tranformations The subject of macros is reasonably complex (but well worth learning) please ensure you have at least read the macro introduction before reading this section. PPWIZARD provides a mechanism to hold macro data in one format but transform this data when tranformed, this removes the need to hold the same data in multiple formats. Transformation commands all start with $$ and apply to: 1. Macro Replacement Macros parameter where they were supplied on a reference without a value that and begin with '$$' have special meaning, they are commands to PPWIZARD. The command applies to the complete contents of a macro before any replacement of parameters has occurred. 2. Macro Parameter Replacement Restriction Note that most of the above '$$' commands work directly on the contents of the macro (after parameter substitution). If the contents (or parameters) contained macros then you may not get the desired affect. The Available $$ Tranformations In the following list "Bold $$ commands" apply to both macro and parameter replacement, "Dark Green $$ commands" only apply to macro replacement and "Magenta $$ commands" only apply to macro parameter replacement:  $$ADDCOMMA The parameter will be formatted using AddCommasToDecimalNumber().  $$ASIS The value of the macro is substituted EXACTLY as it is, there is no substitution of macro parameters etc. Note that this will not prevent any macros the contents refers to from being expanded.  $$AQ You use this command to surround your parameters data with quotes. The quotes used are double or single quotes, if neither can be used ppwizard will go through a whole list of alternative 'quote' characters, if none of these can be used then ppwizard will terminate.  $$DSQ You use this command to surround your parameters data with quotes. The quotes used are double or single quotes, if neither can be used ppwizard will terminate.  $$HTMLQ The parameter is all or part of a string surrounded by double quotes, any double quotes that exist in the data should be converted to """.  $$IGNORE The parameter will be "dropped" (a empty string will be substituted). The main reason you might want to do this is to prevent a '"{$?}"' type parameter from including this parameter.  $$LOWER The parameter will be converted to lower case.  $$RX' This can be very useful if you wish to use the value in a rexx string which is surrounded by single quotes. It makes sure that the value will not break any rexx rules. Note that there is also a '$$RX"' variant for use in double quoted rexx literals.  $$RXEXEC The value is taken to be rexx code to be executed. The value to be substituted should be returned in the "RXEXEC" variable.  $$SPCPLUS A space is added before the start of the value if it is non-empty.  $$SQX2 The value is modified such that all single quote characters are doubled up. This can be very useful if you wish to use the value in a rexx string which is surrounded by single quotes as rexx will in this situation treat the two single quotes as a single single quote that does not terminate the string.

It should be noted that under regina there is a limitation that a long string could break so I now recommend the use of "$$RX'" instead.  $$PASSDSQ The parameter will be quoted as per the $$DSQ command and the parameter name followed by the equal sign will be added to the start. This is handy when one macro uses another and a parameter needs to be passed to the inner macro (parameter has same name in both macros).  $$PASSAQ The parameter will be quoted as per the $$AQ command and the parameter name followed by the equal sign will be added to the start. This is handy when one macro uses another and a parameter needs to be passed to the inner macro (parameter has same name in both macros).  $$SDQ You use this command to surround your parameters data with quotes. The quotes used are single or double quotes, if neither can be used ppwizard will terminate.  $$UPPER The parameter will be converted to upper case.  $$? If the '$$' command is otherwise unknown you can create your own formatting (ie you can not redefine an existing format). To define a format you need to define a macro which contains the rexx formatting code. The macro must have the name of "REXX_$$" followed by the name of your command, for example to use the command "$$TO_C_STRING" you would create "REXX_$$TO_C_STRING". The value to be formatted is in the "TheValue" variable. If required you can also determine the source of the value (macro or parameter name) as it is stored in "TheName" (for case insensitive items it is in upper case). For macro parameters only the name of the macro being expanded is in the "TheMacro" variable. Note that the quoting routines above do more than just make your code "prettier", without using these commands you have to decide on a quote character yourself and then a parameters value must never contain this character. These special commands won't solve all quoting issues (remember parameter processed left to right - imbedded parameters are not processed first) however they will make life much easier. EXAMPLE - $$ Parameter Replacement Lets make sure that parameters 2 and 3 in the following macro get translated to upper case: ;--- Define macro --------- #define SimpleTest P1={$parm1}, P2={$parm2="parm1_default" $$upper}, P3={$parm3 $$upper $$DSQ} ;--- Expand macro --------- <$SimpleTest Parm1='value1' Parm2='value2' Parm3='value3'> EXAMPLE - $$ Macro Replacement A simple example where if the "$$SQX2" command were not used that ppwizard would fail (in this case with variable "A" unknown trap): #define TheMacro The value 'A' is in quotes #evaluate "" "call Summary 'VALUE', '<$TheMacro $$SQx2>'" Another example where we wish to add commas to a rexx variable: Value = Here is another example which may be useful if you were creating 'C' code and maybe other situations: ;--- Define directory (non 'C' format as used elsewhere) --- #define DIR_NAME C:\DB\PROJECTS\FRED ;--- Define a macro to transform a string into 'C' format --- #DefineRexx REXX_$$TO_C_STRING TheValue = ReplaceString(TheValue, '\', '\\'); TheValue = ReplaceString(TheValue, '"', '\"'); TheValue = ReplaceString(TheValue, d2c(10), '\n'); TheValue = ReplaceString(TheValue, d2c(13), '\r'); TheValue = ReplaceString(TheValue, d2c(7), '\b'); #DefineRexx ;--- Use our defined transformation --- StringC = "<$DIR_NAME $$TO_C_STRING>"; ═══ 8. Dependancies ═══ Dependancies If you know what a make file does then this is basically the functionality PPWIZARD is trying to supply. Once you have built your output files you don't need to rebuild them unless you modify one of your source files. PPWIZARD actually does a very much better job than any make-file-based process. Let's consider a very complicated example where: 1. The source file is called "INPUT.IT". 2. It #includes "MACROS.IH". 3. For some stupid reason it reads in line one of "CONFIG.SYS". 4. It creates "OUTPUT.OUT" and "ALSO.OUT". 5. You have many other ".IT" files with their own dependancies. The whole process might take a while. You really only want to preprocess the above 3 input files to produce the 2 output files if you need to. PPWIZARD stores information in a dependancy file for each compile which will allow it to check whether a build is required or not. It will detect if any input or output files have changed or if they are missing and begin to rebuild the output. To conditionally make your ".IT" files you could use: ppwizard *.it /output:out\*.htm /CrLf /DependsOn:Depends\*.dep This command says to make "*.IT" and put all output into the "OUT" directory and creates a "DEPENDS" directory and places dependancy information in this directory. Most dependancies can be handled by the preprocessor but sometimes you need to help identify the input and output files. For example, you probably used a REXX linein() command to read from "CONFIG.SYS", you will need to use the #DependsOn command to indicate this one. In a similar manner, the example generates 2 output files; if you used the REXX lineout() command to create these then you would again need to use the #DependsOn command to indicate this output dependancy. Filter It is possible to tweek the contents of the generated file by creating a rexx macro called "HOOK_DEPENDSON", rexx variables involved are:  DepIn This is an array that holds each input dependancy. If you set an item to "" then it will be dropped (no need to compress the array). Note that any item that starts with "*" is not actually a file!  DepOut This is an array that holds each output dependancy. If you set an item to "" then it will be dropped (no need to compress the array).  DepDrop If you wish to tell PPWIZARD not to generate the file at all then set the value to non-blank, the value should be the reason which will show up in any debug output. An example of a hook which ensures that no output dependancies are recorded follows: #DefineRexx 'HOOK_DEPENDSON' ;--- Don't generate any output dependanies ------------------------------- DepOut.0 = 0; ;--- Clear specific input dependancy ------------------------------------- ;;;DepIn.1 = ''; ;;Changing to blank saves having to compress array ;--- Don't create dependancy file after all ------------------------------ ;;;DepDrop = "Changed my Mind"; #DefineRexx Since in this case PPWIZARD does not know about the output dependancies you can safely manipulate or delete these without ppwizard remaking them. In general I don't recommend this approach but it is another option for you. ═══ 9. Commands ═══ Commands PPWIZARD has a lot of different commands and features, you could cover basic requirements (enough to get you well and truely started) with the "#include" command which includes external files and "#define" would allow you to start with simple macros or symbolic variables (these allow more reuse than simple file inclusion allows). The next step up from this is to look at conditional generation of code ("#if" etc), as an example this can be useful where there are two or more variations in how a header or footer should look. Note that you may wish to use the /HideCmd switch if you use a WYSIWYG editor. The following is a complete list of what is available to you when you use the PPWIZARD Preprocessor:  #AsIs  #AutoTag  #AutoTagClear  #AutoTagState  #debug  #define[+|?]  #DefineRexx[+]  #DependsOn  #ElseIf  #EndIf  #EOF  #error  #evaluate[+]  #if  #IfDef  #IfNDef  #import  #include  #Info  #intercept  #MacroSpace  #NextId  #OnExit  #option  #output  #OutputHold  #push  #pop  #require  #RexxVar  #transform  #UnDef  #warning  #(  #)  #Unknown Commands The following commands allow you to perform PPWIZARD looping:  #{  #}  #break  #continue ═══ 9.1. #( ═══ #( This command provides a simple way to spread a long line of over many lines without the need for line continuation characters at the end of each line. Basically you define a block, within this block all lines are combined with the character(s) you chose used to separate the lines. Note that if some lines within the block need different line separators, you can still use the normal line continuation characters for these lines! An alternative method is to nest this command where multiple separators are required. It is recommended that you do not use this command to handle rexx code, use the #DefineRexx command instead. Note that the restriction of on long imbedded ppwizard command mentioned in the line continuation section also applies here. You can use this command to surround the definition of a macro, however the first line (The "#define[?|+]" command) must not end with a line continuation character. PPWIZARD will detect the definition and will ensure a space is used for the separator and not the "Separator" character sequence you defined. This command can't itself be used in a macro! If you try to do this the most likely result is being told that ppwizard does not understand the '#)' command. Syntax [WhiteSpace]#( [["]Separator["] [["]EndBlockMarker["]]] If the Separator parameter is supplied it defines the zero or more characters that separate each line within the block. The default separator is a space. If the EndBlockMarker parameter is supplied this determines the text that marks the end of the block, this can be any text and by default is "#)" (note that the current prefix is used). Lines are combined until this text is located (in this exact case). This command used to be called "#OneLine" and you should replace all occurances. EXAMPLE - Basic Demo #( '' Line 1 Line 2 #( ' ' '$$$' ;;"nested" block (block ends at '$$$') This is Line 3 $$$ This \ is Line \ 4 Line 5 #) EXAMPLE - Repeat Block In a jetform JMD (Job Management Database) we needed to define 82 lines for each product (only a subset of this is shown in the example) so we defined this macro: ;--- Define the template for a "Product Summary" --- #define ExpandMacro <${$#1}> #( '' #define ProductSummary ===[ Product Summary ]======================================== === Product: {$Product} === MDF: {$Mdf} === Input Tray: {$InputTray} === Defined at: Line of ============================================================== !f {$Product}_F_1 RIGHTFAX """<$DirJfForms>\{$MDF}.mdf"" -afxon -aip2 -agvFAX_MESS=1" * 1 T SSPPGGET * * C * !f {$Product}_F_1 RIGHTFAX """<$DirJfForms>\{$MDF}.mdf"" -afxon -aip2 -agvFAX_MESS=1" * 1 T SSPPGSET * * C * ... ... !f {$Product}_P Optra """<$DirJfForms>\{$MDF}.mdf"" -afxon -aip1 -ati20<$ExpandMacro =^{$InputTray}^>" * 1 T SSPPGGET * * C * !f {$Product}_P Optra """<$DirJfForms>\{$MDF}.mdf"" -afxon -aip1 -ati20<$ExpandMacro =^{$InputTray}^>" * 1 T SSPPGSET * * C * #) ;--- Define the input paper trays used --- #define LIGHT 3 #define DARK 4 We then use the above macro: <$ProductSummary Product="PROD19" MDF="PSMORT" InputTray="DARK"> ... <$ProductSummary Product="PROD40" MDF="PSGENERAL" InputTray="LIGHT"> ... <$ProductSummary Product="PROD73" MDF="PSGENERAL" InputTray="LIGHT"> ═══ 9.2. #) ═══ #) There is no such command although it may at first glance appear so. The text "#)" is simply the default end of #( block marker if no alternative was specified. If you find ppwizard telling you that there is no such command then that is perfectly correct. The fault is that the block commands can not appear in a macro. This "command" used to be called "#OneLineEnd" and you should replace all occurances. ═══ 9.3. #{ ═══ #{ This command is used to define the start of a loop which ends with the "#}" statement. Loops can be used within a macro. Syntax [WhiteSpace]#{ [FOR RexxVariable = Start TO End] or [WhiteSpace]#{ [SET [COUNTER RexxVar] ["]SetSpec1["] ...] The syntax directly supports simple "for" loops and "set" loops, for more complicated requirements you would need to do your own end of loop processing. The #continue command can be used to restart at the top of the loop and #break will cause you to exit the loop. FOR Loops Probably fairly obvious but you are looping through all integers from a starting point and incrementing by one until the ending point is reached. SET Loops The idea behind a set loop is that you have one or more sets of values which you'd like to process, effectively this can provide a nested loop like functionality. A set is simply an array containing items (possibly created using Add2() or ArraySplit()). In general having duplicated entries would make no sense but this is no validated. If a set specification contains an equals sign then you wish to create a set of data by splitting the string after the equal sign. By default a space is used as a delimiter, to override this preceed the string with '{Delimiter}'. Leading and trailing whitespace is always removed and blank items ignored. If set "a" contains 10 items, set "b" contains 3 and set "c" contains 4 and you specified "SET A B C" then the loop will be executed 10x3x4=120 times as every combination will be processed. To access the current values of the sets within the loop you use rexx variables "SET_A", "SET_B" and "SET_C". The names must be valid as rexx symbols. There is no built in limit on the number of set items and the left most item varies slowest until the right most which varies fastest. If you specify a "COUNTER" name then you can use this variable within the loop, it will start at one and increment for each combination processed. Restrictions 1. Both the start and end of a loop must occur within the same input file. 2. Loops can't be nested (within a single file). If you need to nest loops you can either use the #include command to include a file which then itself contains a loop or you do a bit of rexx programming. 3. Since PPWIZARD loads the whole loop without processing lines in between the affect of any intermediate "HashPrefix" option is ignored for the purposes of finding the end of the loop. Example 1 - Create 99 Printers in a Jetform JMD This creates 99 printer definitions in a Jetform JMD, looking similar to: !p PRINTR01 PRINTR01 PRINTR01/q "-afx... ... !p PRINTR99 PRINTR99 PRINTR99/q "-afx... The code to generate these printer definitions is: ;--- Define 99 SSP Printers --- #RexxVar SspPrinter = 1 #{ ;--- Make sure we use "01" - "99" --- #if [ < 10] #evaluate ^^ ^SspPrinter = '0' || SspPrinter^ ;;Does not affect addition #endif ;--- Create the printer --- !p PRINTR PRINTR PRINTR/q "-afxon -apfon -axpson -asplex616p -rYES -aduON" 50 ;--- Finished? --- #RexxVar SspPrinter + 1 ;;Add 1 to count #if [ > 99] ;;Finished? #break ;;Created all printers! #endif #} The above again but this time using a "for" loop as well as using a macro replacement tranformation (this is slower): ;--- Simple transformation to product 2 digit (minimum) integers --- #DefineRexx REXX_$$0PadTo2 TheValue = TheValue + 0; ;;Strip off excess spaces and leading zeros if TheValue < 10 then ;;Has less than 2 digits? TheValue = right(TheValue, 2, '0'); ;;Left pad to 2 digits #DefineRexx ;--- The code to produce 99 printer definitions --- #{ for SspPrinter = 1 to 99 ;--- Create a printer --- !p PRINTR PRINTR PRINTR/q "-afxon -apfon -axpson -asplex616p -rYES -aduON" 50 #} Example 2 - Test "SET" loop The following code shows 4 different variations on how set data can be created and specified. #DefineRexx '' ;--- Create SET "A" --- A.1 = '1' A.2 = '4' A.3 = '7' A.0 = 3 ;;Number of Items in set "A" ;--- Create SET "B" --- call ArraySplit 'B', 'apple orange' #DefineRexx ;--- Use the "sets" created above ------------------------------------------- #RexxVar NUMLOOPS = 0 ;;Loop counter (Better way demonstrated below) #{ SET A B #RexxVar NUMLOOPS + 1 . A = "" , B = "" #} ;--- Create sets as part of the loop command -------------------------------- #{ SET counter NUMLOOPS \ ^A=1 7 9 11^ \ ^B={,}aaa,bbb,ccc,ddd,eee,fff^ . A = "" , B = "" #} Example 3 - Read File Until End This example is used to load a list of languages and to create a directory for each ones generated html. The languages file looks like: en ;;English it ;;Italian fr ;;French The code (OS/2 only) to read the above file and create the directories is: ;--- Define some directories --- #define site.root C:\sitetest #define site.out.dir <$site.root>\html ;;output root ;--- Initialization --- #DefineRexx '' ;--- Load standard rexx library --- call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' call SysLoadFuncs ;--- Make required base directories --- MkDirRc = SysMkDir('<$site.root>') MkDirRc = SysMkDir('<$site.out.dir>') #DefineRexx ;--- Make language directories --- #define LanguageFile "LANG.IH" ;;Note in this case would be more CPU efficent if rexx variable #DependsOn INPUT <$LanguageFile> #evaluate "" ^CloseFileRc = stream(<$LanguageFile>, 'c', 'close');^ #{ ;--- Exit on EOF --- #if lines(<$LanguageFile>) = 0 #break #endif ;--- Read the language line, strip out comment and make directory --- #evaluate "" "MkDirRc=SysMkDir('<$site.out.dir>\' || '), 1)>')" #} #evaluate "" ^CloseFileRc = stream(<$LanguageFile>, 'c', 'close');^ ═══ 9.4. #} ═══ #} This command is used to define the end of a loop the start of which must also occur within the same input file. Please see the "#{" command for an example and more information. ═══ 9.5. #AsIs ═══ #AsIs This command is frequently used to allow you to #include real working code as examples. Any modifications required to get the file (or part of) to display "as is" occurs automatically as programmed by you. Turning on "asis" mode basically allows you to read in text without PPWIZARD getting in the way. More than this is can simplify issues such as the fact that the viewer may not be able to display certain characters unless converted. For example a html viewer may have trouble with '<' characters unless they are converted to '<'. Turning "asis" mode on will modify a number of PPWIZARD #Options so that lines will get passed through "as is". This means blank lines are kept, line comment and continuation is ignored and a number of other options may be modified. Use "#Debug" to see all that are modified. While #AsIs mode is turned on, PPWIZARD commands are still processed. This is fine if your examples either don't include ppwizard commands or you wish to conditionally include parts of the example. If you did not want this you would need to use the "HashPrefix" option or take some other action to prevent it. You may need to do more than this to get the effect you desire. For example to have have the lines appear in a HTML browser as they do in your source you will need to do more work (or blank lines get removed and long lines wrap etc). The minimum you would require for HTML is to use

 & 
tags around the lines. Using "
" as mentioned above only handles part of your issues with a HTML 
browser, any html tags such as "

" will get interpreted by the browser and generate a new paragraph. This is fine if that was your intention however you probably wish to see the characters "

" in the browser. You could make use of the "#AutoTag" or "#AsIs" autotagging facility to convert all occurrances of "<" to "<". It's normally more flexible to have basic autotagging such as that mentioned for the "<" character handled by this command and any extensions to the fundamental changes handled by the "#AutoTag" command. You would also wish to check out the "#AutoTagClear" & "#AutoTagState" commands. There are some tricky bits that you may need to handle - such as how do you tell PPWIZARD where the end of the example code is. If you are not careful any end of example marker you place could get autotagged in such a way that PPWIZARD will not recogise it! This can be tricky, to see examples of how this can be handled, see my "OL_DOC.DH" header file which handles examples for IPF and HTML examples. All AsIs tagging is performed before "#AutoTag" tagging. As mentioned earlier it can be difficult or impossible (in some situations) to escape out of an "example" mode that you set up. It will help you to remember that all autotagging is case sensitive and only occurs on data as it is read from a file (not on lines from memory/macros). If you don't get the results you expect you will need to use "#debug" or "/debug" to watch what occurs. In debug mode lines from a file are show in a similar manner to "0012:" where a line from memory could be shown as "####:". Like autotagging you must be very careful in the order that you tag things for example specifing that '<' gets replaced with '<' and then that '&' gets replaced with '&' is wrong as you would be tagging the '<' from the first replacement. For the example given here you would need to swap the order, in other cases you may need to use an intermediate 'unique' string and convert it back as the last change. If possible try and group changes so that all single character changes are together this allows PPWIZARD to perform faster replacments as it can make good use of the BulkChar2String() routine. Syntax [WhiteSpace]#AsIs ["]SETUP["] ["]NAME["] OR [WhiteSpace]#AsIs ["]OFF["] OR [WhiteSpace]#AsIs ["]ON["] [["]NAME1["] ...] The "SETUP" command is used to store all currently defined "#AutoTag" commands under the "NAME" you supply. The existing AutoTags are cleared. The "OnOrOffCommand" specifies whether or not "asis" mode is on. When turning #AsIs mode on you may specify one or more named sets of tags that were previously set up with "SETUP". Example - SETUP ;--- Setup minimum tagging for IPF lines --------------------------------- #AutoTagState + ;;Lets not effect current tags #AutoTag "&" "&." #AutoTag ":" "&colon." #AsIs SETUP IpfAsIsChanges ;;Copy tags and clear (name tags "IpfAsIsChanges") #AutoTagState - ;;Restore Original AutoTag state Example - Including Example File The following is an example of a macro which will display an example file with a nice border and title (in a table). The included file does not contain conditional commands etc (or if it does we want to see it as part of the example). This is one example of a macro you could use: #define IncludeExampleFile \
\ \ \ \
{$TEXT} \
\
                                 \
                                       \
               #AsIs       ON HtmlAsIsChanges        \
               #AutoTag    ON                        \
               #option     PUSH HashPrefix="#$@!"    \
               #$@!include "{$FILE}"                 \
               #$@!option  POP   ;;Restore Prefix    \
               #AutoTag    OFF                       \
               #AsIs       OFF                       \
                                              \
               
\
Prior to using the above macro we need to have defined up the "HtmlAsIsChanges" tagging. This could have been done as follows: #Autotagstate + ;;Lets not stuff up any existing autotags #AutoTag '<' '<' ;;Browser may not display text unless '<' etc changed. #AutoTag '>' '>' #AsIs SETUP HtmlAsIsChanges ;;Remember tagging we wish to take place #Autotagstate - ;;Restore previous autotag state Now lets use the above macro (and do some automatic tagging): #AutoTagClear #AutoTag "REM " 'REM ' #AutoTag /SET / *SET * #AutoTag "set " ~set ~ <$IncludeExampleFile FILE="C:\AUTOEXEC.BAT" TEXT='Example file "C:\AUTOEXEC.BAT"'> Note that in the example above all existing autotags were cleared before setting our own. This is restrictive and intelligent use of the "#AutoTagState" command will be more useful. ═══ 9.6. #AutoTag ═══ #AutoTag This command allows you to automatically modify text. This is mainly handly when "#AsIs" mode is on and you are including text which you don't wish to modify (such as a real live working module you wish to use as an example). By default the search operation is case sensitive and a simple textual replacement occurs. There are other options such as case insensitive replacements that you can set using the AtChangeType option. When used with the "#AsIs" command you can include real working code as examples and link parts of this working example to your explanations. Automatic tagging is not recommended for general use as it can greatly decrease performance of this program. AutoTag definitions are applied to lines in the order of declaration in a single pass. This means that you can make use of common "macro" like tags but they must be defined later than all references. If AutoTags are used while "#AsIs" mode is off then it can generate references to #define variables and they will be expanded. You can temporarily hide or extend the existing autotag list with the "#AutoTagState" command. You can clear all or some AutoTags with "#AutoTagClear". Only lines that come directly from a file are tagged. Macro contents are safe. Autotagging occurs after any required "#AsIs" tagging. The parameters shown below do not have macros expanded before this command processes them. This ensures that complex macros can be handled. The replacement will occur after the autotag text has been replaced. Syntax #1 [WhiteSpace]#AutoTag ["]OnOrOffCommand["] This form of the command turns on or off the automatic tagging of text. The "OnOrOffCommand" parameter should be "+", "ON" or "YES" to keep leading whitespace otherwise use "-", "OFF" or "NO". Syntax #2 [WhiteSpace]#AutoTag ["]BeforeText["] [ ["]AfterText["] [#Slot]] The "BeforeText" is translated into "AfterText". Note that the "AfterText" can contain the "BeforeText" and both can contain absolutely any characters. If the "AfterText" parameter is missing (not empty) then the first autotag for "BeforeText" is deleted. Note that "AfterText" can contain the string "{$AT}" which will get replaced with the value of "BeforeText". The optional "Slot" parameter can be used to adjust the ordering of the tag. Normally the new tag is placed after all existing ones, to make it first specify "#1". A tag of "#2" would ensure it's the second change etc. Note that it's perfectly legal and in some cases may be required that you specify the same "BeforeText" more than once. When "#AsIs" mode is on you need to be very careful about what you use as replacement text, for example if you wish to see a '<' character you will actually need to use '<' instead! Example In the following example we are including "C:\AUTOEXEC.BAT" and wish to create hypertext links from the "REM" command to "rem.htm" and from the "SET" command to "set.htm". Note that I expect my source to contain "set" or "SET" but not "SeT" etc. Also note that to eliminate the chance (in this example certainty) of clashes with future #defines I use the text ">$<" to split up the file "set.htm". Also note that I look for "SET" and not "SET ", this is silly as it would also match on "SETTLE" or other similar text and not just "SET" commands which I know need at least one space. #AutoTagClear #AutoTag "REM " 'REM ' #AutoTag /SET/ *SET* #AutoTag "set" ~set~ #AutoTag "><" "" #AutoTag ON <$IncludeExampleFile FILE="C:\AUTOEXEC.BAT" TEXT='Example file "C:\AUTOEXEC.BAT"'> #AutoTag OFF ═══ 9.7. #AutoTagClear ═══ #AutoTagClear This command allows you to clear out unwanted #AutoTags that you probably used to tag a previous sample so as not to interfere with the next one. By default only the current autotag state is cleared so it is possible to be selective about the clearing of tags with intelligent use of the #AutoTagState command. Syntax [WhiteSpace]#AutoTagClear [["]ALL["] ] If the literal value "ALL" is specified the autotag state is cleared as well as all tags. The default is to only clear autotags defined in the current state. ═══ 9.8. #AutoTagState ═══ #AutoTagState This command can be used to create autotag "pools" which can be selectively used and cleared without affecting any previously defined pools. This allows a self contained macro to create, use and clear autotags and still restore the state so as not to affect the rest of the system. This command also saves and restores whether or not tagging was on. A common use of this command is to temporarily hide all autotags, another is to make a temporary copy then delete one or more tags, perform some tagging and then restore the original state. Syntax [WhiteSpace]#AutoTagState ["]Name["] OR [WhiteSpace]#AutoTagState ["]Mode["] [["]REMEMBER["]] OR [WhiteSpace]#AutoTagState ["]+["] ["]REMEMBER["]|["]Name["] ... It is possible to name a state at any time. When you increment the state the name will be remembered as the "Name" you supply. When incrementing to a new state you can copy tags from one or more named states. The "Mode" parameter should be either: 1. "+" This saves the current state. By default the new state has no tags available. If the literal value "REMEMBER" is also used then the new state has access to all tags available in the previous state. You can also specify one or more previously defined state names to copy their tags. Note that if #AutoTagClear is used (without 'ALL') in a state where "REMEMBER" was also used then this will only clear tags that you have defined in the current state (not all tags available in that state). 2. "-" This restores the previous state. If the literal value "REMEMBER" is also used then the new (previous) state's tags are replaced with those currently available. EXAMPLE #Autotagstate FirstState ;;Name this state #AutoTag "1" "one" ;;Create a tag #Autotagstate + ;;Create new state (no tags available) #Autotagstate SecondState ;;Name this state #AutoTag "2" "two" ;;Create a tag #Autotagstate + REMEMBER ;;Create new state (get access to last states tags) #AutoTag "2" ;;Delete this tag #Autotagstate + ;;Create new state (no tags available) #Autotagstate + FirstState 'SecondState' ;;Create new state (copy tags from 2 states) #Autotagstate - REMEMBER ;;Go back to previous state (overwriting any tags it might have) #Autotagstate - ;;Go back one state (keep that states tags) #Autotagstate - #Autotagstate - ═══ 9.9. #Break ═══ #Break This command is used to exit a PPWIZARD loop (similar to rexx 'leave' loop instruction). Please see the "#{" command for an example and more information. ═══ 9.10. #Continue ═══ #Continue This command is used to immediately restart a PPWIZARD loop from the top (similar to rexx 'iterate' loop instruction). Please see the "#{" command for an example and more information. ═══ 9.11. #Debug ═══ #Debug This will turn debug mode on or off. Debug mode is normally off but can also be turned on with the /debug command line switch. Note that this command will not adjust the debugging mode if the /debug switch was used. The output is fairly easy to understand and aims to actually teach (or help you to understand) certain commands (such as #import). Syntax [WhiteSpace]#Debug ["]OnOrOffCommand["] The "OnOrOffCommand" should be "+", "ON" or "YES" to turn debug on otherwise use "-", "OFF" or "NO". Example #debug on ... ... #debug 'no' ═══ 9.12. #define[+|?] ═══ #define[+|?] A #define can be used to define a value (constant) once and then refer to it elsewhere. It allows you to update one place and have all necessary change flow though to all the statements that refer to it. If ppwizard discovers that you are about to redefine an existing variable then: 1. If the command was "#define" a warning is generated. The reason for this is because it is assumed you did not expect this. You could be reusing a macro that belongs to someone else (hidden in a header you use) or you may have made some kind if mistake. 2. If the command was "#define+" then you are expecting to override a variable and so no warning is generated. I recommend you don't use this command for general use. 3. If the command was "#define?" then the defintion is aborted. This is useful in your header files where the user is allowed to override default values. For more information on macros and their use please see the macros section. There are some situations where you may wish to use the #AutoTag facility instead. The main difference is with a #define'd variable you indicate where the replacement will occur - if it can't do it the build fails, when using #AutoTags the replacement occurs automatically but it may not always come out the way you wish and of course no error if it "fails" (use of #defines is also very much faster). I mainly use #AutoTag when I'm including real working code from a file and I want to created hypertext links or highlight sections. I can then quickly change the example without having to worry about having to retag it. You should also have a look at the #evaluate command which can do things that a #define can't. Note that there are some extreme situations which you will not be able to wrap up in a #define (or at least easily). As an example of a situation which will be very difficult (if not impossible) would be to include a reference to a macro which then uses the #AsIs command, also be careful with #AutoTag. commands. In these situations you can use a #Include command to perform the textual replacement. The DefineMacroReplace option affects how this command works. Syntax The syntax of this command is different from most others as it does not accept quoted strings, the reason for this is to ensure that you can include 'C' header files with a bit of care (allowing sharing of the common header). [WhiteSpace]#define[+] Variable Contents The "Variable" is the name of the macro and when seen in following lines will be replaced by the contents. If the macro you are creating contains ppwizard commands then you must use the line continuation characters and place each ppwizard command on a line of it's own. The "Contents" is basically the rest of the line and is what is placed into the output. This may contain any number of mandatory or optional parameters. The line containing a #define does not itself have variables substituted. What this means is that if the "Contents" contains other definitions, the values of these at the time of use will be used. If this is not what you wish then use the "#evaluate" to create the definition. Note that for ppwizard commands (within a #define) to be executed when the macro is expanded the commands must be on their own line. Please see the multi line macros section. I highly recommend that you read the whole section on macros. I get a reason amount of emails from people who haven't.... You can redefine a variable if you wish. Example 1 - No Parameters Used ;--- #define some standard stuff -------------------------------------------- #define Img100%PureJava {100% pure Java} #define ImgFreeIbmVisualAgeJava {Free Visual Age Java} #define ImgBarbedWire

;--- Now use some #defines -------------------------------------------------

Paragraph before barbed wire. <$ImgBarbedWire>

Paragraph after barbed wire. Example 2 - Parameters Used ;--- Define an image ------------------------------------------------------- #define AnImage ;--- Refer to image twice, each with different size ------------------------

Image at Size 1 = <$AnImage WIDTH="100" HEIGHT="33">

Image at Size 2 = <$AnImage WIDTH='200' HEIGHT=|66|> ;--- Define an image ------------------------------------------------------- #define AnImage2 > ;--- Refer to the image supplying any and all parameters -------------------

Image = <$AnImage2 All=/ALT="{An Image}" WIDTH="100" HEIGHT="33"/> ;--- Refer to the image supplying NO parameters ----------------------------

Image = <$AnImage2 All=""> Example 3 - Contains Logic ;--- Define a macro that can be used to include my example files ----------- #define IncludeExampleFile \
\ \ \ \
{$TEXT} \
\
                                 \
                                         \
                 #AsIs    ON                           \
                 #include "{$FILE}"                    \
                 #AsIs    OFF                          \
                                                \
                 
\
<$IncludeExampleFile FILE="Example.TXT" TEXT='Example file "EXAMPLE.TXT"'> Example 4 - Default Parameters ;--- Define a stupid macro which defaults some parameters ------------------ #define AMacro /{Parm1}/{Parm2="Default2"}/{Parm3=+Default3+}/ ;--- Use the macro --------------------------------------------------------- <$AMacro Parm1='Text1'> <$AMacro Parm1='Text1' Parm2=*Text2*> ═══ 9.13. #DefineRexx[+] ═══ #DefineRexx[+] This command provides a simple way to define multi line/statement rexx code without requiring line continuation characters. This is useful for: 1. Defining rexx code to be executed at some later stage (if not immediately). 2. Defining a fragment of rexx code which may act much like a subroutine. 3. Defining rexx code (or fragments) for generating into the rexx program you are creating (/rexx). You use this command to define the start and end of a block of rexx code and anything in between is either rexx code or a ppwizard command. The fact that ppwizard commands are interpreted while the block is being processed allows you to use useful commands such as #include or #if to selectively include or exclude parts of the rexx code (at definition time). To make decisions at runtime you must use the rexx "if" statement and not the ppwizard #if command! Each line of rexx goes through the following processing: 1. The line goes through all normal PPWIZARD processing except symbol substitution. This means for example that line continuation occurs so that a "line" that this command sees can actually be made up of many source lines. 2. All leading and trailing whitespace is removed. 3. A trailing rexx comment if it exists is removed. 4. A trailing ';' is removed if it exists. 5. If the line starts with "$trace" (any case) then if the command:  is "$trace off" then tracing of following code is not allowed.  is "$trace on" then tracing of following code is again allowed. Note that this command does not turn on $tracing.  is "$trace" then the following command will be traced.  is "$trace SomeText" then the the text will be displayed. Please see /$Trace for more information and for details on restrictions. If debug is off then this command will be ignored. 6. Unless you specify otherwise the line is packed and you should be aware of some of the restrictions involved (described below). Packing reduces the chance that the rexx interpreter you are using will reject the code due to clause or line length restrictions. The packing also means that you can format the code to be easier to read (since you aren't worried about the extra spacing etc). 7. The line is added to any previously collected (separated with ""). This seperator string is automatically handled if the rexx is executed under ppwizard control. If you generate the rexx code (into the output rexx program) then the default is that it is converted to a newline. Note that the end of each rexx line is expected to be the end of a rexx statement so if a rexx statement spans multiple lines you will still need to use line continuation on these lines. Note that if you combine multiple macros generated this way you must separate them with ';' as this command does not terminate the last statement. At the end of the block the complete rexx code may have symbols substituted depending on how the DefineMacroReplace option is set. Note that the last line/statement of the block will not be terminated with a semicolon, if you wish to combine blocks you will need to take this into account. Syntax [WhiteSpace]#DefineRexx[+] [["]Variable["] ["]NOPACK["] ["]$TRACE["] ["]$TRACE_OFF["]] If the command was "#DefineRexx+" then if a redefine of a variable occurs then this is considered to be OK and no warnings are generated. If the Variable parameter is supplied it defines the name of a #define to be generated with the following lines as their contents. If no parameters are supplied the rexx code block is completed. If the Variable parameter is given as "" (empty) then the rexx code is immediately executed and not saved. When code is executed immediately then any macro parameters are always replaced. The "$Trace" option on this command indicates that you wish to trace all rexx commands in the block. The "$trace_off" command turns off all tracing for the code. Please see /$Trace for more information and for details on restrictions. This command is ignored if debug is not on. The default situation is that rexx code is packed, the optional NOPACK keyword allows you to prevent this. Some rexx interpreters have trouble with legal rexx code when excess spaces are removed! Rather than completely disabling all packing you can also make use of the AllowPack option to selectively prevent the packing of certain lines. Use Within Macros The line by line processing described above can not occur when the rexx code is being defined within a macro (it sees one line). I recommend that you do not use this command within a macro definition unless this command is used for the immediate execution the rexx code. If defining a macro containing rexx code then there is no reason why it need be imbedded. You need to end each line with either a ";" or space as appropriate, consider the following: #( '' #define EnclosingMacro ... #DefineRexx 'Something' Var1 = '' if (Test) then do fred = 1 end #DefineRexx ... #) The rexx code actually ends up looking like: Var1 = ''if (Test) thendofred = 1end It was the "#(" command which did this, not the "#DefineRexx" command (it only sees the one "line"!). Now to fix it you could ensure a ";" was on each line, in the following I use a space also (purely for example): #( '' #define EnclosingMacro ... #DefineRexx 'Something' Var1 = ''; if (Test) then \ do; fred = 1; end; #DefineRexx ... #) Now the line will look like(ignoring any packing that "#DefineRexx" might do: Var1 = '';if (Test) then do;fred = 1;end Much better! This is valid rexx and so should work! Debugging You can turn on rexx's inbuilt tracing by ensuring that you have set the "REXXTRACE" DebugLevel and setting the "REXXTRACE" macro to an appropriate value. This tracing does not work well on regina (excellent on OS/2 though). To simply test a few spots for correct function typically you would use standard rexx "say" commands like: say 'About to do stuff, Line = "' || TheLine || '"'; A better method to do the same thing is to use the "$trace" facility, the command would now look like: $trace About to do stuff The above "$trace" would display the string and dump the contents of all known variables. It would also be possible to set breakpoints and the values at the end of the execution of the rexx code also get displayed. Now you can also turn on "$trace mode" where $trace commands are automatically added to each line however you should read about the (reasonable) restrictions you should follow when formatting your code. MORE ON PACKING The preprocessor packs well written code (by my definition!) and can fail to correctly pack code where strings are appended without the use of the "||" operator (as the excess spaces will be removed). For example the following statement will not create the string you expect when packed: BothPartsCombined = 'Value:' TheValue; The following statement is a version of the above that will work: BothPartsCombined = 'Value: ' || TheValue; Note that PPWIZARD may not be able to correctly pack lines that refer to macro variables such as in the following: #DefineRexx ValidateUrlR_REXX_Location #Option PUSH AllowPack=NO do IncIndex = 1 to ;;This line can't be packed #Option POP ;--- Format the input file at this level --- ThisBit = _filespec('name', InputComponentLevel(IncIndex)); ThisBit = ThisBit || '(' || AddCommasToDecimalNumber(InputComponentLineLevel(IncIndex)) || ')'; ;--- Update location string ---------------- if IncIndex = 1 then UrlSourceLocation = ThisBit; else UrlSourceLocation = UrlSourceLocation || '->' || ThisBit; end #DefineRexx The reason for the failure to pack (without the #option commands) in this circumstance is that the rexx code is not valid until the substitution has taken place, this confuses the packing logic (it is not packing "pure" rexx code). EXAMPLE #DefineRexx SomeRexxCode $trace ;--- Comment to be removed (as are blank lines) --- $trace At start of rexx code RexxVar1 = strip(GetEnv('PATH')); /*--- This rexx comment will also be removed ----*/ RexxVar2 = '[' || 'stuff'; /*This rexx comment gets removed*/ ;--- Lets not pack the following rexx code --- #option PUSH AllowPack=OFF BothPartsCombined = 'Value:' TheValue; #option POP ;--- Gets some code from a file --- #include "SomeRexx.X" #DefineRexx #evaluate ^^ ^<$SomeRexxCode>^ You could also have a look at the PPWSORT.H header file as a further example. ═══ 9.14. #DependsOn ═══ #DependsOn This command can be used to indicate a dependancy that is not obvious to PPWIZARD. All input and output files seen by PPWIZARD are automatically taken care of but there may be instances where you might need to indicate other files. As an example of an INPUT dependancy, you might have a macro which reads parts of CONFIG.SYS (only you know why!) using the rexx linein() function, because your generated output is dependant on the contents of CONFIG.SYS you will wish to rebuild if the file changes. As an example of an OUTPUT dependancy, you might not wish to use the #output command and therefore directly write to files using a rexx "lineout()" function. A file input dependancy should be defined before the file is used as this ensures that ppwizard can detect changes to the input file even while it is executing. It does not matter when an output dependancy is defined as the timestamp is only read at completion. If /DependsOn was not specified then the command is ignored. Syntax [WhiteSpace]#DependsOn ["]DepType["] ["]StampWhat1["] ... The "DepType" parameter indicates should be one of:  INPUT The following information is an input dependancy. Note that PPWIZARD can look at other things and not just input files (as explained below). The rexx AddInputFileToDependancyList() routine can also be used.  OUTPUT The following file(s) are output (target) file dependancies. The rexx AddOutputFileToDependancyList() routine can also be used.  TEMP The following file(s) are temporary files and should be ignored. This must be used before a file is marked as an input or output dependancy. The rexx AddTempFileToDependancyList() routine can also be used. A rebuild or your target files is required if there are any input files which have a later date/time than any of your output files. A rebuild is also forced if an input or output file can't be located. The "StampWhat" parameter(s) are usually the names of files that should be added to the dependancy list. It is not an error (just time consuming) to specify the same item more than once. Normally a files date and time is used for the "stamp" however if the parameter (for an INPUT dependancy) starts with '*' then this has special meaning as follows:  *CmdLine Use this to indicate that you wish ppwizard to examine the command line switches (masks ignored). If different switches were used then a remake is required. This dependancy is on by default (see the /DependsOnComplete switch).  *Exec=CommandLine This allows a you to process any command that can be typed at a command line. Its redirected output, stripped of carriage return, Line Feed and End Of File characters is used as the "stamp".  *Expires=When This indicates that at some time in the future you wish to force a rebuild. The "When" parameter has the same syntax as the offset passed to the TimeStamp() routine except that you can use "NOW" to represent 0 (always rebuild).  *Files=[+]FileMask This allows a list of files matching a mask to be stamped in one hit. Unlike simple stamping of individual files this uses the mask to determine differences so it will detect file additions and not just deletions and modifications to already known files. For example "*Files=+E:\DB\URLS\*.*" will stamp all files in the directory, and since "+" was used will also process those in it's subdirectories.  *PpwPgm Use this to indicate that you wish ppwizard to rebuild if the version of ppwizard changes in any way. This dependancy is on by default (see the /DependsOnComplete switch).  *Rexx=Expression(s) This allows a you to process some rexx and return a value. The value to be used should be returned in the rexx variable DepValue, if your rexx code does not include "DepValue" (any case) then it is assumed to be a single rexx expression which can safely be assigned to that variable. One good example of how to use this is where your build depends on the value of an environment variable (although in this case a "*Exec" of the "set" command would also work in most operating systems).  *Today Use this to indicate that you do not need a rebuild today but you would tomorrow. One example of why you might want to do this is my DLCNTR ppwizard add-on where it marks "new" downloads if they are recent, I need to check if recent every day. Example 1 - Two files specified #DependsOn INPUT "C:\CONFIG.SYS" "C:\STARTUP.CMD" Example 2 - Assorted Commands #DependsOn INPUT '*TODAY' ;;Rebuild tomorrow #DependsOn INPUT '*EXPIRES=1w' ;;Rebuild in another week #DependsOn INPUT '*EXPIRES=3H' ;;rebuild in 3 hours #DependsOn INPUT '*EXPIRES=NOW' ;;Must always rebuild #dependson INPUT "*CMDLINE" ;;If command line switches change #dependson INPUT "*PpWPGM" ;;If ppwizard program changes in any way #dependson INPUT ^*Rexx=getenv('ppwizard_include')^ ;;If the environment variable changes Example 3 - Real life macro ;--- Outputs the size of a file (takes parameter "File") -------------------- #define SizeOfFile \ #evaluate+ LocalFileName ^ReplaceString("../{$File}", "/", "\")^ \ #DependsOn INPUT "<$LocalFileName>" \ #evaluate+ TmpFileSize ^AddCommasToDecimalNumber(stream("<$LocalFileName>", "c", "query size"))^ \ #if "<$TmpFileSize>" = "" \ #error $Failed getting size of "<$LocalFileName>"$ \ #endif \ <$TmpFileSize> #define SizeOfFileInSmallFont {$Before=""}<$SizeOfFile File=*{$File}*> bytes{$After=""} #define (SizeOfFileInSmallFont) <$SizeOfFileInSmallFont File=*{$File}* Before='(' After=')'> ═══ 9.15. #elseif ═══ #elseif This command is used if you wish to have some lines included when the #if condition is false. ═══ 9.16. #endif ═══ #endif This command is used to terminate a previous #if command. There should be a matching #endif for every #if command. ═══ 9.17. #EOF ═══ #EOF This command marks where processing of the current file should be stopped. Anything after this command can be in any format as it's never read. This command is ignored if it appears in an #imported file. Syntax [WhiteSpace]#EOF [["]EndifCount["]] The "EndifCount" parameter is optional and may be required if you wish to use the #EOF command conditionally. The number should normally match the nesting level within the file. ═══ 9.18. #evaluate[+] ═══ #evaluate[+] This command will execute a rexx command line. The result of this command can be stored into a "#define" variable. If the command was "#evaluate+" then if a redefine of a variable occurs then this is considered to be OK and no warnings are generated. For more information on macros and their use please see the macros section. You would use this command (over #define) for one of the following main reasons: 1. You wish to get some some data from rexx. Any standard rexx functions (or your own as ".CMD") can be used. If you are frequently calling your own routine for performance you may wish to look at the #MacroSpace command. 2. You wish to perform arithmetic or other similar operation. 3. You wish the macros contents to have leading or trailing whitespace. 4. You wish to get some information out of the environment (contents of environment variables, information from text or INI files etc). The #evaluate command will handle syntax errors and unknown variables, dumping what it knows and then aborting the preprocessing. It is recommended that you read the performance documentation as this command is much slower than some other alternatives which you can use in some circumstances (such as the #define command). Syntax [WhiteSpace]#evaluate[+] ["]Variable["] [']Expression['] The "Variable" parameter is the name of the macro you wish created or updated. This parameter is optional if you don't wish to use the result as text in your HTML. If supplied the result of the "Expression" is assigned to the macro specified. The "Expression" parameter is executed by rexx. It is highly recommended that for all but trivial amounts of rexx code that you define the rexx code with the #DefineRexx command. As well as supporting all standard rexx functions and any ".CMD" you care to write yourself there are many ppwizard defined Rexx Extensions that you can make use of. EXAMPLE #1 ;--- Get current date ------------------------------------------------------ #evaluate TodaysDate "date('WeekDay') || ' ' || date('Normal')" EXAMPLE #2 ;--- Get SHORT name of Generated HTML file --------------------------------- #evaluate ShortNameHtml "_filespec('name', '')" EXAMPLE #3 ;--- Beep and then generate first 3 lines of CONFIG.SYS into HTML ---------- #evaluate "" "call beep 1000, 800" #evaluate "" 'File2Read = "C:\CONFIG.SYS"' #evaluate "" "CloseFileRc = stream(File2Read, 'c', 'close')" #evaluate "ConfigSysLine1" "linein(File2Read, 1)" #evaluate "ConfigSysLine2" "linein(File2Read)" #evaluate "ConfigSysLine3" /linein(File2Read)/ #evaluate || /CloseFileRc = stream(File2Read, 'c', 'close')/ <$ConfigSysLine1>
<$ConfigSysLine2>
<$ConfigSysLine3>
═══ 9.19. #Error ═══ #Error This command allows you to halt processing and display an error message to explain the problem. The #Warning command is similar but does not halt processing. Syntax [WhiteSpace]#error [']ErrorMessage['] The "ErrorMessage" specifies the text to be displayed. The text can contain "{NL}" to cause a line break. Example #if GetEnv('FRED') <> 1 & GetEnv('FRED') <> 2 #error "Invalid value for variable 'FRED'" #endif ═══ 9.20. #if ═══ #if A #if command (like #ifdef and #ifndef) can be used to conditionally include lines of text, this can be any other type of line or command except #elseif or #endif. As an example of its use, #if allows you to examine the machine it is running on (for example its environment variables) and generate the appropriate code. #if commands can be nested to any level and there need not be any lines between a #if and a #endif or #elseif command. There are two forms of this command. The second exists only to speed up the performance, it supplies a small subset of the full functionality but is very much faster. Syntax #1 - Full Functionality (but slower) [WhiteSpace]#if ValidRexxCondition The "ValidRexxCondition" specifies a valid rexx conditional test which results in a TRUE or FALSE answer. The condition may be as complex as you wish and may include the special GetEnv() function (or many others) to obtain information from the environment. For complex logic an external rexx script could be called, these can return numeric or text return codes. Syntax #2 - Partial Functionality (but fast) It is recommended that this form be used where possible if you have many tests in your code, if you only have a few you probably don't need to bother. This form does a single compare between two simple values. The square brackets surrounding the compare are used to indicate that this form is supplied by the user. [WhiteSpace]#if [Value1 Operator Value2] The "Operator" parameter should have whitespace to either side and be one of the following: 1. == Strict compare for equal. 2. = Compare for equal. 3. <> Compare for not equal. 4. < Less than. 5. > Greater than . 6. <= Less than or equal. 7. >= Greater than or equal. The Value1 & Value2 parameters can be one of the following:  A rexx number.  A rexx variable.  A rexx literal. Example #1 ;--- Don't not display following graphics on works INTRANET! ---------------- #if translate(GetEnv("PRJSRCDIR")) = "E:\DB\PROJECTS\HOMEPAGE"

#endif Example #2 #define StupidExampleMacro \

Hi, my name is Dennis Bareis and I have been using OS/2 and developing for \ #if ['<$AtWork>' = 'Y'] \ ANZ \ elseif \ *WRONG INC* \ endif \ on and off since the original 1.0 version. ═══ 9.21. #ifdef ═══ #ifdef A #ifdef command (like #if and #ifndef) can be used to conditionally include lines of text, this can be any other type of line or command except #elseif or #endif. #if commands can be nested to any level and there need not be any lines between a #if command and a #endif or #elseif command. Note that this command only checks on a single variable, for more complex requirements you will need to use a #if command along with calls to the Defined() routine. For performance reasons it is recommended that you use #ifdef and #ifndef commands where possible. A common use of this command is as a method of creating block comments. Simply specify a variable you know does not exist! Syntax [WhiteSpace]#ifdef VariableName The "VariableName" specifies a variable that should exist for the test to evaluate to true. Example #1 #define Fred FredsValue #ifdef Fred ... #endif Example #2 - Block Comment #ifdef DoesNotExist

This paragraph has been commented out as we are testing for a variable we know does not exist. #endif ═══ 9.22. #ifndef ═══ #ifndef A #ifndef command (like #if and #ifdef) can be used to conditionally include lines of text, this can be any other type of line or command except #elseif or #endif. #if commands can be nested to any level and there need not be any lines between a #if command and a #endif or #elseif command. Note that this command only checks on a single variable, for more complex requirements you will need to use a #if command along with calls to the Defined() routine. For performance reasons it is recommended that you use #ifdef and #ifndef commands where possible. Syntax [WhiteSpace]#ifndef VariableName The "VariableName" specifies a variable that should NOT exist for the test to evaluate to true. Example #define Fred FredsValue #ifndef Fred ... #endif ═══ 9.23. #import ═══ #import Many programs and databases (Microsoft Excel or Access, Lotus 123 etc) allow you to export data in many different formats. The #import command allows you to import the most common formats and generate output to your specification. The default output format for quite a few of the import types is a HTML table. Not only don't you need to generate a table at all, you also have a lot of fine tuning parameters if you wish to remain with a table but just wish to tweek its look (give certain columns a special background color etc). I have seen people generate a whole series of #define and #include commands to generate a separate html page for each record (from a product database). This command might seem complicated at first (and in actual fact it is!), I recommend you actually try the examples (cut and paste as required). If you are having problems working out what is going on I highly recommend the use of debugging (/debug or #debug) as this has been designed not just for debugging but for training as well. Note I recommend that if debugging you cut your database down to a few test records so that you won't be swamped with output. Import Processing Details All import types get handled in two distinct passes as follows: 1. The imported file is read, processed (including calls to your rexx filter code if defined) and the output is generated to a temporary file. If you have a filter then in some advanced applications you may need to use the WriteLineToTmpImportFile() routine. An example of this is if you wished to generate PPWIZARD commands such as #output. 2. The temporary file is read in and processed in exactly the same manner as any file that you yourself might include with a #include command. This is where any macros you may have referenced are expanded. By default, if debug is not on then after pass two completes the temporary file is deleted. Turn debug on and examine the temporary file if things are not going to plan! This will tell you at which of the 2 stages your import is failing to work correctly. Syntax [WhiteSpace]#import ["]File2Import["] ["]T2H|WRAP["] ["]DefineName["] OR [WhiteSpace]#import ["]File2Import["] ["]ImportType[-]["] ["]DefineName["] ["]FieldInfo1["] ... The parameters are as follows: 1. File2Import This is the name of the file to be imported. Blank lines are ignored (is this causing anyone problems?). 2. ImportType This describes the format of the data to be imported. If the type has "-" appended then the first lines of the file are dropped (default is one line). The currently supported types are:  SQL PPWIZARD can perform any SQL query you like and process the resulting rows.  CMA[-] All fields are comma delimited (fields can't contain commas unless quoted). Fields may be empty. Blank trailing fields may be missing.  TAB[-] As above except a tab (ascii 9) is the delimiter.  ???[-] As above except you specify the exact delimiter you want. For example "^^^" indicates that you wish a delimiter of "^".  FIX[-] Unlike all previous types there is no delimiter. Items appear in fixed columns in the file. While you can play with "FieldInfo" there is not much point as you can specify all the fields you want in the order you want them.  ML Each record spans multiple lines and ends with a blank line. Each field takes up a line and specifies a field name and a value separated by a user defined delimiter ('=' by default).  T2H This is a text to HTML type import.  WRAP This is a specialised import facility. You get passed a line at a time and you decide how to handle it. 3. DefineName This parameter gives you a lot of control over how your output is generated. The value you supply here is used as a prefix for all your import options. As an example, if you specified "FRED" as a value then some import types would look for a #define of "FRED_DROP_BLANK_LINES" to see if you wished to override the default handling of blank lines. The exact #define options which are available will differ depending on the import type. If you specified a blank value for the prefix a default is used. The name of the default also varies with import type but for the common types is "IMPORT". In some cases such as when HTML tables are generated there are multiple levels of defaults and changing a lower level one may have no effect if you also override a higher one. This is because the lower level values became the default values for the higher level. As an example there is no point specifying that record columns should have a background color of green and then overriding the record generation default! Again the use of debugging support will generally make this clear as it will show PPWIZARD looking for all options and display the value PPWIZARD has decided to use. ═══ 9.23.1. #import - Delimited Records ═══ #import - Delimited Records This type of #Import has clearly defined fields. You would frequently wish to display these in a table (say in a HTML page) however nothing says that you need to do so. If you wish to create macros and then #include a template file then that is also possible. Within a record the fields are delimited by a single character such as a tab or comma. Note that under Windows you have the option of reading these sorts of files via ODBC and therefore you can use an SQL import! This gives you greater control without extra coding such as controlling sorting the data or only choosing records that match certain criteria (as per normal SQL query syntax). Field Information Parameters On these types of imports "FieldInfo" follows the "DefineName" parameter on the #import command line. You must specify field information for each field up to the last one you are interested in. The field information is of the format: [{NewColumn}]TitleText The optional "NewColumn" specifies the column you wish the field to be moved to. This need only be supplied if you wish to change the order, by default the first field is column 1 etc. The "title text" specifies the value for the field in the header record. A blank "title" is used to indicate that we don't require a field and it should be dropped. DEFINITIONS/OPTIONS If you can't understand how these options work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_BLANK_FIELD Normally a blank field will be displayed as blank. You may wish to display '-' instead. Another possiblity is to display a 1 by 1 transparent gif so as to have table borders around blank fields look better. For even more control (probably rare requirement): - DefineName_BLANK_COLUMN_? This allows you to specify different blank replacement values for each column.  DefineName_DROP_BLANK_LINES You can specify whether or not blank lines (or lines where all fields are blank) are significant. The default is 'Y' to drop blank lines, specify 'N' to prevent this.  DefineName_NEWLINE_CHAR This can be used to determine what newlines within fields should be replaced with ("
" by default).  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_DROP_LINE_COUNT If we are dropping lines (TAB- command etc), then how many should be dropped. The default is one.  DefineName_BEFORE You would probably only use this define if you didn't want to generate a table at all. You may specify the string "{$Columns}" which will get replaced with the number of fields to be displayed. If this define is not used then you can use the following: - DefineName_TABLE_ATTRIBS This value allows you to specify all HTML attributes of the table apart from the number of columns.  DefineName_HEADER This is used to control the "code" which handles the "heading" record, this does not have to be a html table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_HEADING_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_HEADING_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_HEADING_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_HEADING_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_HEADING_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_HEADING_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_RECORD This is used to control the "code" for each record, this does not have to be a html table. You would definately define this option if you didn't want a html table, you might wish to create s series of #defines or maybe you are not generating html at all and need to generate an IPF table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_RECORD_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_RECORD_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_RECORD_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_RECORD_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_RECORD_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_RECORD_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_AFTER Unless you are not creating a table you are unlikely to want to change the codes that end the table.  DefineName_RECORD_FILTER The contents of this variable should be one or more rexx expressions. Normally all records are displayed. A filter can examine all column variables and modify them or tell PPWIZARD to ignore the record. The filter is not called for the heading record. The following rexx variables and functions are relevant: - Remove If this variable is set to any non blank value then the record will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - Column.? The "Column" array holds the data for each field (that you are interested in) of the current record in the order you provided. For example "Column.2" holds the 2nd column's data. Note that "Column.0" holds the number of fields in the array. - Dropped.? The "Dropped" array holds the data for each field (that you dropped) of the current record in the order that they were dropped. For example "Dropped.1" holds the first dropped field. Note that "Dropped.0" holds the number of fields in the array. - ThisRecordsCodes This variable gets initialized for each record with the value that you defined (or allowed to default) for the "DefineName_RECORD" option. You can add to or modify this record in any way. The value of "{$Column1}" gets replaced with the contents of the rexx variable "Column.1" etc. If all your records are processed the same way then you should not need to modify this variable. It is useful where you might want the output (row of table) to look different depending on the records data. In some cases this can be better done by updating the rexx "Column.?" array. If you need multiple lines you can of course use "" where required. - WriteLineToTmpImportFile() The passed data is written to the output file, any line feed characters will indicate the end of a line. - RecordFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_KEEP_TMP_FILE Normally PPWIZARD keeps the temporary file it creates while importing when debug is on. This option allows you to specify whether you do or don't want the file kept (whether debug is on or off).  DefineName_DO_PASS_2 You would rarely wish to modify this value. It controls whether or not the generated file is #included (pass 2), it's value defaults to 'Y'. You might wish to disable the processing if all your processing can be done in pass one (for example you have imported a database into memory.  DefineName_PROTECT_START By default will be set to the value . If you have filter code that wants to generate PPWIZARD commands then you will need to override this value. Have a look at the multiple HTML pages example.  DefineName_PROTECT_END By default will be set to the value . You should also check out an example of importing a file into multiple HTML pages based on the contents of one of the fields. Examples - Comma Delimited A tab delimited file is probably be best format to use however this example will use comma delimited as it's a bit hard to display a tab! Assume the following file is being imported (Importme.CMA): Dennis,Bareis,Programmer Wendy,Buxton,Librarian Fred,Nerk,Idiot Please treat each of the following examples in isolation and assume that no #defines other than those specifically shown for that example have been set. Please note that I could have used ",,," instead of "CMA" when specifying the format. The following code will display the 3 fields in the order they occur (in a completely default table format): #import IMPORTME.CMA "CMA" '' "First Name" "Last Name" "Job" We now wish to simply swap the order of the "Job" column so it becomes first: #import IMPORTME.CMA CMA '' "{2}First Name" "{3}Last Name" "{1}Job" Lets drop the last name altogether so that we only see the first name and job columns: #import IMPORTME.CMA CMA '' "First Name" "" "Job" Lets display the above table using slightly different table formatting (column borders thinner, table border fatter, headings centered on yellow background and record data left justified): #define IMPORT_TABLE_ATTRIBS BORDER=20 CELLSPACING=1 #define IMPORT_HEADING_COLUMNS ALIGN=CENTER BGCOLOR=YELLOW #define IMPORT_RECORD_COLUMNS ALIGN=LEFT #import IMPORTME.CMA CMA '' "First Name" "" "Job" As above but column 2 is centered: #define IMPORT_TABLE_ATTRIBS BORDER=20 CELLSPACING=1 #define IMPORT_HEADING_COLUMNS ALIGN=CENTER BGCOLOR=YELLOW #define IMPORT_RECORD_COLUMNS ALIGN=LEFT #define IMPORT_RECORD_COLUMN_2 ALIGN=CENTER #import IMPORTME.CMA CMA '' "First Name" "" "Job" Examples - More Complex This example is based on a real one situation at work. We export date from Microsoft's access/Excel and want this data to appear in a table. The following main points are demonstrated: 1. The use of #defines and line continuation to format things to be easier to read and understand. 2. The use of #autotag to translate some of the text (for example "priority") to minimize the width of the columns. 3. More complex overriding of defaults to get smaller font size etc. 4. More field dropping but also swapping of fields. ;--- Problem database data exported from Excel (trying from access) ---------

Release 98.0.1

;--- Setup table definitions ------------------------------------------------ #define IMPORT_TABLE_ATTRIBS BORDER=5 CELLSPACING=1 #define IMPORT_BLANK_FIELD - ;** CommentBlock /* (Tuesday 23/06/1998, 13:00:55, by Dennis_Bareis) */ ;**+-------------------------------------------------------------------------- ;**|#define IMPORT_HEADING_COLUMNS ALIGN=CENTER BGCOLOR=YELLOW ;**|#define IMPORT_RECORD_COLUMNS ALIGN=CENTER ;**|#define IMPORT_RECORD_COLUMN_2 ALIGN=LEFT ;**|#define IMPORT_RECORD_COLUMN_4 ALIGN=LEFT ;**+-------------------------------------------------------------------------- ;** /* (Tuesday 23/06/1998, 13:00:55, by Dennis_Bareis) */ ;--- Define some data translations (shorten Priority + Problem Type) -------- #AutoTag ">High<" ">H<" #AutoTag ">Low<" ">L<" #AutoTag ">Medium<" ">M<" #AutoTag ">Change<" ">C<" #AutoTag ">Error<" ">E<" ;--- Try these -------------------------------------------------------------- #define IMPORT_HEADER -\ {$Column1} -\ {$Column2} -\ {$Column3} -\ {$Column4} -\ {$Column5} -\ {$Column6} -\ {$Column7} -\ {$Column8} -\ #define IMPORT_RECORD -\ {$Column1} -\ {$Column2} -\ {$Column3} -\ {$Column4} -\ {$Column5} -\ {$Column6} -\ {$Column7} -\ {$Column8} -\ ;--- Specify the fields ----------------------------------------------------- #define FIELD_NAMES "{1}Problem
#" \ "{2}Title" \ "{5}P
r
i" \ "{8}Pre
/
Spar" \ "{6}T
y
p
e" \ "{3}Application" \ "" \ "" \ "{7}Fixed By" \ "" \ "" \ "" \ "" \ "" \ "{4}User Impact" ;--- Make the changes (autotag some text) ----------------------------------- #AutoTag ON #import "export.tab" TAB- "" <$FIELD_NAMES> #AutoTag OFF Examples - IPF Import The following code: #define IMPORT_NEWLINE_CHAR .br #define IMPORT_BEFORE :table cols='15 15 10'. #define IMPORT_HEADER :row. -\ :c.:hp9.{$Column1}:ehp9. -\ :c.:hp9.{$Column2}:ehp9. -\ :c.:hp9.{$Column3}:ehp9. #define IMPORT_RECORD :row. -\ :c.{$Column1} -\ :c.{$Column2} -\ :c.{$Column3} #define IMPORT_AFTER :etable. #define IMPORT_RECORD_COLUMNS ALIGN=LEFT #import "EXAMPLE.CMA" CMA '' "First Name" "Surname" "Job" Produces this IPF table: ┌───────────────┬───────────────┬──────────┐ │First Name │Surname │Job │ ├───────────────┼───────────────┼──────────┤ │Dennis │Bareis │Programmer│ ├───────────────┼───────────────┼──────────┤ │Wendy │Buxton │Librarian │ ├───────────────┼───────────────┼──────────┤ │Fred │Nerk │Idiot │ └───────────────┴───────────────┴──────────┘ Example - Use of Filter #DefineRexx IMPORT_RECORD_FILTER if Column.1 = "Wendy" then Remove='This is "Wendy" record' ;;Don't want this record else Column.1 = translate(Column.1) ;;Make column #1 upper case #DefineRexx #import ImportMe.CMA CMA "" "First
Name" "Surname" "Job" ═══ 9.23.2. #import - Fixed Field Records ═══ #import - Fixed Field Records This type of #Import has clearly defined fields. You would frequently wish to display these in a table (say in a HTML page) however nothing says that you need to do so. If you wish to create macros and then #include a template file then that is also possible. The fields have a fixed starting and ending column. The last record does not need to have a fixed ending column and can span to the end of the line. Leading and trailing whitespace is removed. Field Information Parameters On these types of imports "FieldInfo" follows the "DefineName" parameter on the #import command line. For each field that you are interested in you need to define information in the format: {*,StartingColumn-[EndingColumn]}TitleText In place of the '*' you could specify the column number you wish to place the field but it's usually easier to simply reorder the fields. The "StartingColumn" specifies the column where the field starts. The optional "EndingColumn" specifies where it ends, if not supplied it ends at the end of the line. The first column in a line is column 1. The "title text" specifies the value for the field in the header record. If this "title" is blank the field will be dropped. DEFINITIONS/OPTIONS If you can't understand how these options work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_BLANK_FIELD Normally a blank field will be displayed as blank. You may wish to display '-' instead. Another possiblity is to display a 1 by 1 transparent gif so as to have table borders around blank fields look better. For even more control (probably rare requirement): - DefineName_BLANK_COLUMN_? This allows you to specify different blank replacement values for each column.  DefineName_DROP_BLANK_LINES You can specify whether or not blank lines (or lines where all fields are blank) are significant. The default is 'Y' to drop blank lines, specify 'N' to prevent this.  DefineName_NEWLINE_CHAR This can be used to determine what newlines within fields should be replaced with ("
" by default).  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_DROP_LINE_COUNT If we are dropping lines (TAB- command etc), then how many should be dropped. The default is one.  DefineName_HANDLE_IMBEDDED_NEWLINES Excel and probably other programs can output delimited files where a "line" can contain a newline. To detect this takes more work and so it is not the default situation. To turn on imbedded newline detection use a value of 'Y'.  DefineName_BEFORE You would probably only use this define if you didn't want to generate a table at all. You may specify the string "{$Columns}" which will get replaced with the number of fields to be displayed. If this define is not used then you can use the following: - DefineName_TABLE_ATTRIBS This value allows you to specify all HTML attributes of the table apart from the number of columns.  DefineName_HEADER This is used to control the "code" which handles the "heading" record, this does not have to be a html table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_HEADING_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_HEADING_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_HEADING_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_HEADING_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_HEADING_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_HEADING_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_RECORD This is used to control the "code" for each record, this does not have to be a html table. You would definately define this option if you didn't want a html table, you might wish to create s series of #defines or maybe you are not generating html at all and need to generate an IPF table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_RECORD_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_RECORD_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_RECORD_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_RECORD_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_RECORD_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_RECORD_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_AFTER Unless you are not creating a table you are unlikely to want to change the codes that end the table.  DefineName_RECORD_FILTER The contents of this variable should be one or more rexx expressions. Normally all records are displayed. A filter can examine all column variables and modify them or tell PPWIZARD to ignore the record. The filter is not called for the heading record. The following rexx variables and functions are relevant: - Remove If this variable is set to any non blank value then the record will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - Column.? The "Column" array holds the data for each field (that you are interested in) of the current record in the order you provided. For example "Column.2" holds the 2nd column's data. Note that "Column.0" holds the number of fields in the array. - Dropped.? The "Dropped" array holds the data for each field (that you dropped) of the current record in the order that they were dropped. For example "Dropped.1" holds the first dropped field. Note that "Dropped.0" holds the number of fields in the array. - ThisRecordsCodes This variable gets initialized for each record with the value that you defined (or allowed to default) for the "DefineName_RECORD" option. You can add to or modify this record in any way. The value of "{$Column1}" gets replaced with the contents of the rexx variable "Column.1" etc. If all your records are processed the same way then you should not need to modify this variable. It is useful where you might want the output (row of table) to look different depending on the records data. In some cases this can be better done by updating the rexx "Column.?" array. If you need multiple lines you can of course use "" where required. - WriteLineToTmpImportFile() The passed data is written to the output file, any line feed characters will indicate the end of a line. - RecordFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_KEEP_TMP_FILE Normally PPWIZARD keeps the temporary file it creates while importing when debug is on. This option allows you to specify whether you do or don't want the file kept (whether debug is on or off).  DefineName_DO_PASS_2 You would rarely wish to modify this value. It controls whether or not the generated file is #included (pass 2), it's value defaults to 'Y'. You might wish to disable the processing if all your processing can be done in pass one (for example you have imported a database into memory.  DefineName_PROTECT_START By default will be set to the value . If you have filter code that wants to generate PPWIZARD commands then you will need to override this value. Have a look at the multiple HTML pages example.  DefineName_PROTECT_END By default will be set to the value . You should also check out an example of importing a file into multiple HTML pages based on the contents of one of the fields. Example Assume we have a file as follows (IMPORTME.FIX): First Name Last Name Job Dennis Bareis Programmer Wendy Buxton Librarian Fred Nerk Idiot We note that it has the following fields: 1. First Name, starting in column 1 ending at 18 2. Last Name, starting in column 20 ending at 38 3. Job, starting in column 40 ending at end of line. The following line would import the fields in order (into a completely default table layout): #import IMPORTME.FIX FIX- '' "{1,1-18}First Name" "{2,20-38}Last Name" "{3,40-}Job" ═══ 9.23.3. #import - Multi Line Records ═══ #import - Multi Line Records This type of #Import has clearly defined fields which you label. You would frequently wish to display these in a table (say in a HTML page) however nothing says that you need to do so. Field Information Parameters On these types of imports "FieldInfo" follows the "DefineName" parameter on the #import command line. For each field you have defined in your database you must specify field information. The field information is of the format: {*,FieldName[,FieldOptions]}TitleText In place of the '*' you could specify the column number you wish to place the field but it's usually easier to simply reorder the fields. The "field name" specifies the name you use in your database. It can contain virtually any characters but must of course not contain the delimiter character ('=' by default). Like all PPWIZARD names the name can contain international characters. You can optionally specify some field options which vary the way individual fields are processed. Each field option is separated by a comma, valid options are:  REQUIRED This field is required. You can supply a blank value. This validation occurs whether or not the field is dropped.  NONBLANK This field if supplied must be non blank. If not supplied its value will become blank unless "REQUIRED" option was also specified. This validation occurs whether or not the field is dropped.  NOASIS By default all files go through AsIs() replacements, this option allows you to prevent this occuring on particular fields if required. The "title text" specifies the value for the field in the header record. Since all fields must be defined we use a blank "title" to indicate that we don't require a field and it should be dropped. DEFINITIONS/OPTIONS If you can't understand how these options work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_BLANK_FIELD Normally a blank field will be displayed as blank. You may wish to display '-' instead. Another possiblity is to display a 1 by 1 transparent gif so as to have table borders around blank fields look better. For even more control (probably rare requirement): - DefineName_BLANK_COLUMN_? This allows you to specify different blank replacement values for each column.  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_BEFORE You would probably only use this define if you didn't want to generate a table at all. You may specify the string "{$Columns}" which will get replaced with the number of fields to be displayed. If this define is not used then you can use the following: - DefineName_TABLE_ATTRIBS This value allows you to specify all HTML attributes of the table apart from the number of columns.  DefineName_HEADER This is used to control the "code" which handles the "heading" record, this does not have to be a html table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_HEADING_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_HEADING_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_HEADING_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_HEADING_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_HEADING_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_HEADING_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_RECORD This is used to control the "code" for each record, this does not have to be a html table. You would definately define this option if you didn't want a html table, you might wish to create s series of #defines or maybe you are not generating html at all and need to generate an IPF table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_RECORD_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_RECORD_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_RECORD_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_RECORD_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_RECORD_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_RECORD_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_AFTER Unless you are not creating a table you are unlikely to want to change the codes that end the table.  DefineName_RECORD_FILTER The contents of this variable should be one or more rexx expressions. Normally all records are displayed. A filter can examine all column variables and modify them or tell PPWIZARD to ignore the record. The filter is not called for the heading record. The following rexx variables and functions are relevant: - Remove If this variable is set to any non blank value then the record will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - Column.? The "Column" array holds the data for each field (that you are interested in) of the current record in the order you provided. For example "Column.2" holds the 2nd column's data. Note that "Column.0" holds the number of fields in the array. - Dropped.? The "Dropped" array holds the data for each field (that you dropped) of the current record in the order that they were dropped. For example "Dropped.1" holds the first dropped field. Note that "Dropped.0" holds the number of fields in the array. - ThisRecordsCodes This variable gets initialized for each record with the value that you defined (or allowed to default) for the "DefineName_RECORD" option. You can add to or modify this record in any way. The value of "{$Column1}" gets replaced with the contents of the rexx variable "Column.1" etc. If all your records are processed the same way then you should not need to modify this variable. It is useful where you might want the output ( row of table) to look different depending on the records data. In some cases this can be better done by updating the rexx "Column.?" array. If you need multiple lines you can of course use "" where required. - WriteLineToTmpImportFile() The passed data is written to the output file, any line feed characters will indicate the end of a line. - GetMlField() This routine can be called to obtain the value of a field (the name of which is passed). You can access the fields data in a more efficient manner using the "Column" and "Dropped" arrays however this routine allows you to access a variable knowing its name. - RecordFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_DELIMITER This is the character(s) that separate the name of a field from its value.  DefineName_STRIP_LEADING This indicates whether or not leading whitespace on a fields value should be removed. The default is 'Y', if 'N' one only space is removed if it exists (to allow for a space after the delimiter).  DefineName_SEPARATOR If you continue a field over onto a following line (the continued line has no field name) then what are the two components "stitched" together with? The default is a space.  DefineName_LINE_COMMENT_CHAR This is the character that can be used to start a line for commenting your file. It defaults to the current PPWIZARD line comment character.  DefineName_LINE_FILTER The contents of this variable should be one or more rexx expressions. If an expression is supplied for this option then the filter code will be called for each non comment line found. This allows you to build extra smarts into the processing of records if you wish (for example breaking a table into sections. The following rexx variables are relevant: - MultiLine This is the current line without leading and trailing whitespace. You may modify the contents if you need to. - Remove If this variable is set to any non blank value then the line will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the line. If the contents starts with 'EOF:' then the current line and ALL following are dropped. - LineFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_KEEP_TMP_FILE Normally PPWIZARD keeps the temporary file it creates while importing when debug is on. This option allows you to specify whether you do or don't want the file kept (whether debug is on or off).  DefineName_DO_PASS_2 You would rarely wish to modify this value. It controls whether or not the generated file is #included (pass 2), it's value defaults to 'Y'. You might wish to disable the processing if all your processing can be done in pass one (for example you have imported a database into memory.  DefineName_PROTECT_START By default will be set to the value . If you have filter code that wants to generate PPWIZARD commands then you will need to override this value. Have a look at the multiple HTML pages example.  DefineName_PROTECT_END By default will be set to the value . You should also check out an example of importing a file into multiple HTML pages based on the contents of one of the fields. Example - Multi Line Import Lets assume you have created a database (called "WEBLINKS.ML") similar to: ;--- First record ------------------------ Name : Dennis : Bareis Email : db0@anz.com Web Page : www.labyrinth.net.au Comment : Really good site! ;--- Second record ----------------------- Name: Fredric Bald Comment: This comment contains LT=< & GT=> characters Web Page: www.somewhere.com Email: fred@anz.com Note that in the above sample data the first "name" field spans two lines to demonstrate line continuation. Then you can import the data and convert the email and web addresses into hypertext links with: #DefineRexx ML_RECORD_FILTER Column.2 = "" || Column.2 || "" Column.3 = "" || Column.3 || "" #DefineRexx #define ML_DELIMITER : #import WEBLINKS.ML ML "" "{*,Name}Name" "{*,EMail}Email
Address" "{*,Web Page}http://" "{*,Comment}Comment" The following code imports the same database but demonstrates field reordering (unusual requirement), field dropping (email address is not required) and requiring all fields to be specified and non-blank: #define THIS1_RECORD_FILTER \ Column.2 = "" || Column.2 || "" #define THIS1_DELIMITER : #import WEBLINKS.ML ML "THIS1" "{2,Web Page,required,nonblank}http://" \ "{3,Comment,required,nonblank}Comment" \ "{1,Name,required,nonblank}Name" \ "{*,email}" ═══ 9.23.4. #import - SQL ═══ #import - SQL This type of #Import directly accesses SQL databases such as MS Access 2000, MS SQL Server, mSQL or DB/2. It requires a free 3rd party product called REXXSQL which can be obtained from Mark Hessling's site at "http://www.lightlink.com/hessling/REXXSQL/". To install RexxSQL you will need to follow its instructions but under Windows I simply copied the 2 DLLs into the system directory. PPWIZARD will inform you if it has problems finding the DLL. This command is of course only supported on those operating systems that "RexxSQL" runs on (currently Windows, OS/2 and Unix). Check out Mark's pages for more details on the databases supported however this is a list (may not be complete) of databases known to work with RexxSQL:  IBM's DB2  EasySoft ODBC-ODBC Bridge  Generic ODBC (probably covers most!) - Microsoft Access - Microsoft Excel spreadsheets - Microsoft SQL Server - CSV (and other text formats) - FoxPro - Paradox - DBase  Mini SQL (1.0.16, 2.0+)  My SQL  Openlink UDBC  Oracle (7.x, 8.x)  PostgreSQL  Raima Velocis  Solid  Sybase System 10/11  Sybase SQL Anywhere This form of SQL import should be able to handle all or nearly all of your needs but if you need something more complex then you should check out the accessing SQL in rexx page. If debug mode is on a lot of SQL related information is generated including a dump of all column information available on the columns returned by your query. PPWIZARD's debug mode (by default) also turns on REXXSQL debug so it should be quite easy to diagnose any problems you might have. Field Information Parameters The SQL import requires "FieldInfo" following the "DefineName" parameter. You must specify field information for each column you want to handle from the data returned by your SQL query. The field information is of the format "{ColName}TitleText". The optional "ColName" parameter specifies the column name returned by your query while "TitleText" specifies the value for the title in the header record. If a "ColName" is not specified then the "TitleText" is used for the column name as well. This would probably only be done if you either did not care about the title text in the header or you did not have a header. DEFINITIONS/OPTIONS If you can't understand how these options work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_SQL_DEBUG This value is used to set the RexxSQL "DEBUG" variable. It only takes effect when debug mode is on and by default all available information is output (use "0" for none). Note that RexxSQL debug output is not captured by /ConsoleFile but must be redirected.  DefineName_SQL_USERID Your database may require a user ID for access.  DefineName_SQL_USERPW Your database may require a password for access.  DefineName_SQL_DATABASE This specfies a database. It probably does not specify the database file name but the value has probably been defined somewhere, for example under Windows 2000, to access a database via ODBC the name used here must first be defined in "Start->Control Panel->Administrative Tools->Data Sources (ODBC)".  DefineName_SQL_SERVER Another field which might be required to establish a database connection.  DefineName_SQL_COMMANDS Use this option to execute SQL commands after a connection has been established but before your query has been run. You specify a list of macros (which contain the actual commands) separated by spaces. A command should begin with "-" if errors from it should be ignored.  DefineName_SQL_QUERY This is the actual query itself.  DefineName_BLANK_FIELD Normally a blank field will be displayed as blank. You may wish to display '-' instead. Another possiblity is to display a 1 by 1 transparent gif so as to have table borders around blank fields look better. For even more control (probably rare requirement): - DefineName_BLANK_COLUMN_? This allows you to specify different blank replacement values for each column.  DefineName_DROP_BLANK_LINES You can specify whether or not blank lines (or lines where all fields are blank) are significant. The default is 'Y' to drop blank lines, specify 'N' to prevent this.  DefineName_NEWLINE_CHAR This can be used to determine what newlines within fields should be replaced with ("
" by default).  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_DROP_LINE_COUNT If we are dropping lines (TAB- command etc), then how many should be dropped. The default is one.  DefineName_BEFORE You would probably only use this define if you didn't want to generate a table at all. You may specify the string "{$Columns}" which will get replaced with the number of fields to be displayed. If this define is not used then you can use the following: - DefineName_TABLE_ATTRIBS This value allows you to specify all HTML attributes of the table apart from the number of columns.  DefineName_HEADER This is used to control the "code" which handles the "heading" record, this does not have to be a html table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_HEADING_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_HEADING_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_HEADING_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_HEADING_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_HEADING_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_HEADING_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_RECORD This is used to control the "code" for each record, this does not have to be a html table. You would definately define this option if you didn't want a html table, you might wish to create s series of #defines or maybe you are not generating html at all and need to generate an IPF table. You can specify the string {$Column?} to represent a fields value (? = number of field where 1 is the first). If this define is not used then you can use the following: - DefineName_RECORD_COLUMNS This value allows you to specify the column (HTML "" tags) information to change alignment or colours of columns. This value becomes the default for all columns. - DefineName_RECORD_COLUMN_? This value allows you to specify the column (HTML "" tags) information to change alignment or colours of specific columns. Another use for this would be to specify the width of a column. This value is only used for column number '?'. - DefineName_RECORD_BEFORE_DATA This value allows you to specify some text to be placed in front of the fields data, for example if you wish to change the font size for each column you might used the value "". This value becomes the default for all columns. - DefineName_RECORD_BEFORE_DATA_? This value allows you to specify leading data on a column by column basis. - DefineName_RECORD_AFTER_DATA This value allows you to specify some text to be placed after the fields data, for example if you wish to change the font size for each column you might used the value "" to close the previous font tag. This value becomes the default for all columns. - DefineName_RECORD_AFTER_DATA_? This value allows you to specify trailing data on a column by column basis.  DefineName_AFTER Unless you are not creating a table you are unlikely to want to change the codes that end the table.  DefineName_RECORD_FILTER The contents of this variable should be one or more rexx expressions. Normally all records are displayed. A filter can examine all column variables and modify them or tell PPWIZARD to ignore the record. The filter is not called for the heading record. The following rexx variables and functions are relevant: - Remove If this variable is set to any non blank value then the record will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - Column.? The "Column" array holds the data for each field (that you are interested in) of the current record in the order you provided. For example "Column.2" holds the 2nd column's data. Note that "Column.0" holds the number of fields in the array. - Dropped.? The "Dropped" array holds the data for each field (that you dropped) of the current record in the order that they were dropped. For example "Dropped.1" holds the first dropped field. Note that "Dropped.0" holds the number of fields in the array. - ThisRecordsCodes This variable gets initialized for each record with the value that you defined (or allowed to default) for the "DefineName_RECORD" option. You can add to or modify this record in any way. The value of "{$Column1}" gets replaced with the contents of the rexx variable "Column.1" etc. If all your records are processed the same way then you should not need to modify this variable. It is useful where you might want the output (row of table) to look different depending on the records data. In some cases this can be better done by updating the rexx "Column.?" array. If you need multiple lines you can of course use "" where required. - WriteLineToTmpImportFile() The passed data is written to the output file, any line feed characters will indicate the end of a line. - RecordFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_KEEP_TMP_FILE Normally PPWIZARD keeps the temporary file it creates while importing when debug is on. This option allows you to specify whether you do or don't want the file kept (whether debug is on or off).  DefineName_DO_PASS_2 You would rarely wish to modify this value. It controls whether or not the generated file is #included (pass 2), it's value defaults to 'Y'. You might wish to disable the processing if all your processing can be done in pass one (for example you have imported a database into memory.  DefineName_PROTECT_START By default will be set to the value . If you have filter code that wants to generate PPWIZARD commands then you will need to override this value. Have a look at the multiple HTML pages example.  DefineName_PROTECT_END By default will be set to the value . Example - Import From MS Access 2000 (ODBC) Here is some sample code which accesses a access database via ODBC and creates a table of the contents (all default look and feel): ;--- Specify the query (this determines the rows and their columns) --------- #define IMPORT_SQL_QUERY \ SELECT * FROM [FullDetails] \ WHERE DeptSeqNo > 4 and DeptSeqNo < 11 \ ORDER BY Department.DepartmentDescription ;--- Perform the SQL import ------------------------------------------------- #define IMPORT_SQL_DATABASE PHASE2 #import "" SQL "" \ "{DepartmentDescription}Department's
Description" \ "{DeptSeqNo}Department
Sequence
Number" The first parameter on the import command is normally a filename but for SQL this parameter should be "". The following shows how you could have executed a couple of commands prior to the above query to generate the view that the above uses (not the best way, but good for an example): ;--- Define a query (probably better hardcoded in database but...) ---------- #define DELETE_VIEW \ -drop table FullDetails #define CREATE_VIEW \ CREATE VIEW FullDetails AS \ SELECT * \ FROM Department ;--- Do the above 2 commands after connecting to the database --------------- #define IMPORT_SQL_COMMANDS \ DELETE_VIEW \ CREATE_VIEW Example - Import From MS Excel Spread Sheet (ODBC) This was tested under Windows 2000 using Excel 2000. You need to do the following (otherwise it is like any other SQL import): 1. As for all ODBC imports you need to define the database as a "ODBC Data Source". 2. The first row of the spread sheet needs to contain the SQL field names. 3. You need to define the sql "table", you do this by defining a range in Excel (Insert->Name). Not being an Excel expert in my testing I hard coded a range, this would be a problem if you added records which extended the number of rows past the end of the range. You could make it cover a really large number of rows and have the SQL query drop blank records or if you know how to define the range better then please let me know! Your query might look like: SELECT * FROM ODBC_TABLE Example - Import From Comma Seperated Value File (ODBC) This was tested under Windows 2000. You need to do the following (otherwise it is like any other SQL import): 1. As for all ODBC imports you need to define the database as a "ODBC Data Source". 2. The first line of the text file must contain the SQL field names. 3. The table name in your query is simply the name of the file you are importing. Your query might look like: SELECT * FROM simple.csv WHERE AGE > 10 ORDER by AGE Example - Create One Page Per Record From Template) In this case we wish to read an SQL database and generate a page for each record using a template file. The template file refers to SQL data via PPWIZARD macros which we will get the import to set up. ;--- Specify database (WIN32 ACCESS DATABASE defined in Control Panel -> ODBC Data Sources) --- #define IMPORT_SQL_DATABASE DefinedInControlPanelOdbc ;--- Specify the query (this determines the rows and their columns) --------- #define+ IMPORT_SQL_QUERY \ SELECT * FROM inventory_test \ ORDER BY short_description ;--- Set up the format of the data the import will generate ----------------- #define IMPORT_HEADER #define IMPORT_BEFORE #define IMPORT_AFTER #define IMPORT_PROTECT_START #define IMPORT_PROTECT_END #define IMPORT_RECORD \ ;--- Create PPWIZARD macros from SQL record's data --- -\ #define+ item {$Column1} -\ #define+ desc {$Column2} -\ #define+ price_r {$Column3} -\ #define+ price_o {$Column4} -\ #define+ desc_s {$Column5} -\ -\ ;--- Create new file and include HTML template ------- -\ #output "<$item>.htm" ;;New HTML file -\ #include "master.htm" ;;Include template -\ #output ;;Close file ;--- Perform the SQL import ------------------------------------------------- #( #import "" SQL "" "{product_no}Product Number" ;;Column 1 "{short_description}Description (short)" ;;Column 2 "{long_description}Description (long)" ;;Column 3 "{price_4}Price 4" ;;Column 4 "{our_retail}Our Price" ;;Column 5 #) ═══ 9.23.5. #import - T2H ═══ #import - T2H This is a text to HTML #import mode (please read the #import documentation before trying to understand this section. This is a recent addition so please consider this import type "beta code" Sometimes you will wish to simply convert a a number of text files to a equal number of html files. In this case you will probably wish to use the /Template switch and create a template for your background colors, titles, headers and footers that you require. TEXT SPECIFIC DEFINITIONS/OPTIONS These definitions are specific to the "T2H" import mode. If you can't understand how they work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_BEFORE These tags are used to set up any tags before the file is included. By default the font size is decreased and "
" (preformated text) 
          mode is set up.  Modify or set to blank (to do nothing) if you wish. 

         DefineName_AFTER 
          These tags are used to set up any tags that are required after the 
          file is included.  This normally undoes anything you started using 
          the previous define. 

         DefineName_BLANK_LINES_TO 
          When text is processed in "PRE" mode (see above) you want to leave 
          blank lines as they are.  If however you set up the before tags to be 
          "

" and cleared the after tags then you could convert blank lines to "

, in this way a blank line indicates the end of a paragraph.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_HTTP_LINK The import mode looks for "http:" type web addresses and by default converts the URL into a hypertext link. You may not wish this so you could clear this variable. You might wish to simply highlight the URL.  DefineName_FTP_LINK The import mode looks for "ftp:" type ftp addresses and by default converts the URL into a hypertext link. Otherwise as per the "_HTTP_LINK" option.  DefineName_RECORD_FILTER This option allows you to modify records before they are written to the intermediate file for processing. The value you supply for this option is a rexx expression that can be interpreted. You could use this to simply drop lines or the data can be modified by you. The following rexx variables are relevant: - Remove If this variable is set to any non blank value then the line will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - T2hLineNumber This is the line number of the current line. Do not modify this variable. - T2hFileLine This is the line as read from the file. Do not modify this variable. - T2hNewLine This is the read in line converted to something that will display well in HTML. May have had email addresses etc tagged. This variable may be modified. - T2hFilter If you don't need to do any more filtering then you can clear this variable. This will improve performance.  DefineName_PROTECT_START By default will be set to the value . If you have filter code that wants to generate PPWIZARD commands then you will need to override this value. Have a look at the multiple HTML pages example.  DefineName_PROTECT_END By default will be set to the value . EXAMPLE This example imports a file and also extends the translation it will perform to include 2 international characters. For no real reason we will also prevent email addresses becoming "mailto" links and simply highlight email addresses in a different color. ;--- Save current Autotag state, set up international conversion, restore state --- #AutoTagState + #AutoTag 'Д' 'ä' #AutoTag 'Й' 'ë' ;;Only 2 for this example #AsIs SETUP INTERNATIONAL_SYMBOLS #AutoTagState - ;--- Update option so as to use the international chars as well as usual conversions - #define T2H_ASIS_TAGGING IMPORT_HTML_BASIC \ IMPORT_HTML_BOXGRAPHIC_TO_BOXTEXT \ INTERNATIONAL_SYMBOLS ;--- Simply for demonstrate puroses, remove email links and make "olive" --- #define T2H_MAILTO_LINK {$Url} ;--- Import the text file --- #import README.TXT T2H "" ═══ 9.23.6. #import - WRAP ═══ #import - WRAP This is a specialised #import facility. WRAP DEFINITIONS/OPTIONS These definitions are specific to the "WRAP" import mode. If you can't understand how they work then I suggest you try using /debug or #debug to watch what variables the import uses etc.  DefineName_DROP_BLANK_LINES You can specify whether or not blank lines (or lines where all fields are blank) are significant. The default is 'Y' to drop blank lines, specify 'N' to prevent this.  DefineName_TAB_CHAR Normally tabs are ignored by the import process. This variable allows you to replace them with something else.  DefineName_ASIS_TAGGING This option can be used to adjust the conversion of what may be problem characters (such as '<' in HTML). By default importing does not handle/convert international characters such as umlauts to html symbols but there is nothing preventing you from doing so. This definition lists zero, one or more names as used on previous "#AsIs SETUP" commands (seperated by whitespace). Clear this definition to prevent all ASIS conversions. Note that you will probably need to override this value (maybe others as well) if you wished to expand any macros that the imported data might contain (by default this is not done).  DefineName_RECORD_FILTER This option switches between 2 alternative ways of handling each line of data as follows: 1. Option Not used The macro you identify with the "DefineName" parameter is passed each line in turn (line passed as the macro parameter "Line"). The line is passed as a rexx statement which when executed will restore the line. Your macro can do anything it likes as it determines what if anything get generated. 2. Option used The rexx code that you specify is called for each line. The following rexx variables are relevant: - Remove If this variable is set to any non blank value then the line will be dropped, the variables value is shown when debugging so it is recommended that the value be the reason for dropping the record. If the contents starts with 'EOF:' then the current record and ALL following are dropped. - WrapLineNumber This is the line number of the current line. Do not modify this variable. - WrapLine This is the line as read from the file. You would normally modify this variable. Example of WRAP Import Assume "PEOPLE.TXT" contains people data of the following form (each record spans 3 lines with blank lines being ignored and little validation of data): Harry 18 male Lisa 20 female Then we could create a simple HTML table as follows: ;--- Define some macros to handle the imported data ---------------------- #define InitMultiLineFieldImport \ #RexxVar RxFieldCount = 0 #define TermMultiLineFieldImport \ #if [RxFieldCount <> 0] \ #error "Incorrectly specified record, have of 3 fields" \ #endif #define EachLine \ ;--- "read" the line (no blank lines) ------- \ #evaluate+ '' ^ThisLine = strip({$Line})^ \ \ ;--- Save information ----------------------- \ #RexxVar RxFieldCount + 1 \ #RexxVar RxField_ = ThisLine \ \ ;--- If end of record then output it -------- \ #if [RxFieldCount = 3] \ is and years old \ #RexxVar RxFieldCount = 0 \ #endif ;--- Start the table ----------------------------------------------------- <$InitMultiLineFieldImport>

;--- Import the data (leaving default at dropping blank lines) ----------- #import "PEOPLE.TXT" WRAP EachLine ;--- End The table -------------------------------------------------------
<$TermMultiLineFieldImport> ═══ 9.24. #include ═══ #include A #include can be used to include another (external) file for processing. This allows you to split a very large complicated html file into smaller logical pieces or more commonly to include standard 'header' files which contain all or most of the common definitions/text. This is a very common method for code reuse and is like the SSI (Server Side Includes) include "virtual" or "file" commands (but can also include fragments or parts of files and is less limiting on the external files location). You can nest to any level however each level adds to the number of open files (unless you use the /Inc2Cache switch) so in reality the nesting level is system dependant. Another problem may be that the rexx intrepreter will have its own limit on how far you can nest files. On OS/2 (and probably other operating systems) there are mechanisms for increasing the numbers of file handles if required. For example on OS/2 version 4 fixpack 6 onwards to increase the numbers of available handles by 30 add "SET SHELLHANDLESINC=30" to your config.sys file. You can call the included file anything you like (including the extension) however I recommend the use of conventions for extensions as this can make it easier to determine the context under which a file is expected to be used. The convention for extensions that I use are as follows:  .IT - Internet Text (source code)  .IH - Internet Header (source code)  .HTM - Generated HTML  .D - Document Main (source code)  .DH - Document Header (source code) It is possible for a header file to validate the release of a preprocessor if it needs to use a feature which may not be available in older release, please see the #require command. Note that there are times when you might wish to share a file between 'C' code and PPWIZARD, you might just wish access to some of the values defined with #define statements. If you can't ensure that all commands (and their parameters) that the 'C' code uses are valid in PPWIZARD then you could: 1. Conditionally include portions (example "#ifndef _PPWIZARD_"). Note that "_PPWIZARD_" is automatically defined by PPWIZARD. 2. Use the #autotag commands to modify the contents on the file (on the fly - not on disk!) to convert invalid statements to valid ones (bit of a hack but would work). It is also possible to include a part of the identified file if you can identify some text which marks the start and end of the parts you wish. The following locations are searched in order, using FindFileInPath(): 1. The Current Directory 2. /INCLUDEPATH.BR Any locations specified with the/IncludePath switch. 3. PPWIZARD_INCLUDE environment variable. 4. INCLUDE environment variable. 5. PPWIZARD Install Directory Syntax [WhiteSpace]#include ["|']FileName["|'] [["]Fragment["]] OR [WhiteSpace]#include [["]Fragment["]] The "FileName" specifies the file to be included. If the filename is or contains #defined variables they will be replaced. Note that the "<" & ">" quoted form is to make it compatible with existing "C" headers so you can use these if you require. The optional "Fragment" parameter can be used to indicate the start and end of the portion of an included file you wish to process. The text must exist on the line immediately before and immediately after the part you need. Note that the comparison is case sensitive on unfiltered text. This parameter allows you to create a single include file from what might have been tens of very small files (fragments). I will use this parameter to contain all my example code for my documentation. Example #include "common.ih" #include 'common.ih' ^^ #include ═══ 9.25. #Info ═══ #Info A #Info command allows you to display an informative message to the user. Similar commands are: 1. #Error 2. #Warning Syntax [WhiteSpace]#Info [']InfoMessage['] The "InfoMessage" specifies the text to be displayed. Example Stupid example follows: #Info "The value "fred" is fine." ═══ 9.26. #intercept ═══ #intercept This command allows you to filter a block of lines as they are read from the input file before ppwizard has done any real processing on them (for example before comments and blank lines have been removed). You can not nest intercept blocks. When defining the start of the block you specify the name of a macro containing the rexx code to be executed for each line. Great care must be taken if the intercept commands are used directly in an input file rather than via a macro as ppwizard will not detect the end of the block unless you are careful. When read from a file the end block command must be in the same case as the start block command (you can use this fact to your advantage if you wish to process ppwizard code which itself might contain the command!). When the end block command appears outside of a macro not only must be case be correct but the line must NOT have any inline comments. The rexx code is passed the "current" line in the FileLine rexx variable. The rexx code may modify the line and can include "" codes to cause line breaks in the generated output file. If you had used newline codes ("d2c(10)") instead then any generated ppwizard commands after the first newline will be executed but these will not cause newlines to be generated in the output file. Syntax [WhiteSpace]#intercept [["]MacroContainingCodeName["]] If the single parameter exists then this marks the start of the block, if missing it marks the end of the block. To start the block you need to supply the name of the macro that contains the transformation code. Example #1 Silly example but shows the basics: ;--- Define the rexx code --- #DefineRexx DoubleUp ;--- Stupid example to create 2nd line based on that from file --- FileLine = Fileline || ' 2nd Copy=>' || FileLine; #DefineRexx ;--- Start block / 3 lines / End block ---- #IntercepT DoubleUp aaaa bbbb cccc #IntercepT You should note the leading whitespace that was not removed on the second lines. Example #2 This shows how (bit primative maybe) you could use the existing example inclusion macros but ensure that long lines get wrapped (this might allow source code displayed in a browser to be printed without losing line ends). ;--- Configuration ---------------------------------------------------------- #define SPLIT_MAX_POS 90 #define SPLIT_MIN_POS <$SPLIT_MAX_POS>-30 ;;Look back for space how far #define SplitEndOld <<<(line continued) #define SplitStartNew >>> #define SplitStartNewChars 3 ;;Represents space used in chars ;--- Define the rexx code ------------------------------------------------------------------------------------------------------------ #DefineRexx BreakupLongLines ;--- Incorrect packing would probably occur due to macros ------- #Option PUSH AllowPack=NO ;--- QUICK check to see if any change required ------------------ if length(FileLine) > <$SPLIT_MAX_POS> then do ;--- Work out indenting of this line ------------------------- NsPos = verify(FileLine, '2009'x); ;;Skip past spaces and tabs if NsPos <= 1 then LineIndent = ''; ;;No indent else LineIndent = left(FileLine, NsPos-1); ;;Use same whitespace (to ensure same tabs/spaces) ;--- Fudge set indent ---------------------------------------- LineIndent = copies(' ', 4) || LineIndent; ;--- Now set up line breaks ---------------------------------- Left = ''; Right = FileLine; MinLng = <$SPLIT_MIN_POS>; MaxLng = <$SPLIT_MAX_POS>; do while length(Right) > MaxLng ;--- Get left part of long line (try to break at space) -- LeftBit = left(Right, MaxLng); SpcPos = lastpos(' ', LeftBit); if SpcPos >= MinLng then BreakPos = SpcPos; ;;Break at the space (Note I decided to not trim whitespace either side) else BreakPos = MaxLng; ;;Can't break at a space ;--- Need to split the line further ---------------------- Left = Left || left(Right, BreakPos) || '*LineBreak*' || LineIndent || '*LineRest*'; Right = substr(Right, BreakPos+1); ;--- Take care of 3 added chars that mark line continuation --- MinLng = <$SPLIT_MIN_POS> - <$SplitStartNewChars>; MaxLng = <$SPLIT_MAX_POS> - <$SplitStartNewChars>; end; FileLine = Left || Right; end; #Option POP #DefineRexx ;--- After "<" and other chars converted, translate markers to tags etc ----- #AutoTagState + #AutoTag '*LineBreak*' '<$SplitEndOld $$SQx2>' #AutoTag '*LineRest*' '<$SplitStartNew $$SQx2>' #AsIs SETUP FixLineContinuation #AutoTagState - ;--- Include header for example support ------------------------------------- #include "HTMLPRE.IH" ;--- Include the example (long lines get wrapped) --------------------------- #IntercepT "BreakupLongLines" ;;Note following line must be not be too long!!!!! <$ExampleFile FILE="2.in" STATE=REMEMBER ASIS=FixLineContinuation> #IntercepT ═══ 9.27. #MacroSpace ═══ #MacroSpace A #MacroSpace command allows you to add or drop rexx procedures from the rexx macro space. This can be useful if you have some rexx code which you frequently call in #if or #Evaluate commands as they should execute faster if they are available in the macro space. Syntax [WhiteSpace]#MacroSpace ["]Command["] ["]RexxSourceFile["] [["]FunctionName["] ] The "Command" should be "ADD" to add to the macro space or "DROP" to remove. It is not an error to ADD or DROP the same code more than once (even in a row). Also note that unless you perform a drop when you have finished using it it will take up space until you reboot OS/2. The "RexxSourceFile" is the name of a rexx source file. It should be a relative or absolute filename that currently exists. The path is not searched. If the optional "FunctionName" is not supplied then the function name is the "RexxSourceFile" without path or extension. Example ;--- Load macro (routine called "ConfigInf" - any case) ----------------- #MacroSpace ADD "CMD\CONFIGINF.CMD" #if ConfigInf('TCPIP_ADDRESS') = '' #Error "A TCPIP address is not available...." #endif ═══ 9.28. #NextId ═══ #NextId The #NextId command is designed to make it easy for you to generate code (for example rexx) with global variable names (rexx or ppwizard variables) that will not clash with others of the same name. It does this by creating a unique namespace. For example you may have a global variable called "string", it may be used in a number of locations (including called subroutines), if no care is taken you may "corrupt" the value. Now in rexx you could use the "procedure" command however there are reasons why you would not want to use it. This command allows you to call the variable by the name "@@string" and have the '@@' (or whatever characters you choose) replaced with a unique identifier. Note that there is only ever one ID in use at any time. Apart from the obvious use of having short unique variable names without risk of clashing with those defined elsewhere in your code you can also protect yourself from clashing with variables that ppwizard uses. Syntax #1 [WhiteSpace]#NextId ["]ON["] | ["]OFF["] This format of the command is to turn OFF (the default state) or ON the Next ID processing state. When turned on, processing resumes with the same counter and other information as specified when processing was turned off. Syntax #2 [WhiteSpace]#NextId [["]ToReplace["] [["]IdMask["] [["]Counter["]]]] This form of the command turns on Next ID processing. The "ToReplace" parameter can be any string (the default being "@@"). This string will be replaced in any line read from a file. A value of "" can be used to indicate that the last used or default value should be used. You must carefully pick this value so that you will never use it in your source code for any other reason (such as in a literal). The use of codes is one way of handling the odd occurance of the string when it is not a Next ID marker. The "IdMask" parameter is used to define how the replacement value should look. The mask would normally contain one "*" character to indicate where the unique number should be placed. A value of "" can be used to indicate that the last used or default should be used. PPWIZARD always adds an underscore to the end of a mask, this is to reduce the chance that they may clash with your normal variables! For example you could specify "GV*" which would generate "GV1_", "GV2_" etc. The "Counter" parameter can be used to supply an initial value for the counter (an integer). It is up to you to ensure that you either change the mask or don't reuse a number. Example The following shows some rexx fragments where I am using Next ID processing to ensure that each routine has it's own variables (which other routines don't also use). ;================= Function1: ;================= #NextId #define @@FRED ... parse arg @@Parm1, @@Parm2 ... @@Result = Function1(1, 2) return(@@Result || @@Parm1 || <$@@FRED>) ;================= Function2: ;================= #NextId #define @@FRED ... parse arg @@Parm1, @@Parm2 ... @@Result = ... return(@@Result) Note that the ppwizard variable "FRED" and the rexx variables "Parm1" and "Parm2" actually have different names between "function1" and " function2" and therefore do not overwrite each overs values. ═══ 9.29. #OnExit ═══ #OnExit This command allows you to register some text which after all other processing is itself processed as if it were read from a file as well as specifying a command to be executed after ppwizard has successfully processed the file. This command is useful in standard header files where rather than requiring a user to use a macro before exiting it can be done automatically. An example of this might be in a common html header file where you use this command to automatically generate a standard footer at the end of your html. The processing does not occur if a fatal error was detected. Syntax [WhiteSpace]#OnExit [#Slot] TheText The "Slot" parameter should be:  A number from 1 to 100 A slot (except the special slot 50) can not be reused. It is used to enable you to tell PPWIZARD the order that 'TheText' should be executed. To have your exit processing occur first use slot 1, to have your processing last use slot 100. Processing occurs in order of slot number and in the case of slot 50 in the order they were specified.  Omitted If not supplied a slot number of 50 is used.  The text "EXEC" This is a ppwizard command which performs exactly the same function as the /Validate switch. The "TheText" parameter can contain macro references but it's meaning depends on the slot parameter:  "EXEC" was used Any macros are immediately expanded and information stored. Format is as specified for the /Validate switch.  Normal Processing Any macros and parameters etc are not expanded until exit processing occurs. If you require a specific slot number in code that others might use I suggest that the slot number be configurable. Any change and all risks are then up to the user. EXAMPLE The following is used in one of my header files: ;--- Register checking macro --- #OnExit <$NestingCheck> The following would generate an error as slot 1 is being reused: ;--- Register checking macro --- #OnExit #1 <$NestingCheck1> #OnExit #1 <$NestingCheck2> ═══ 9.30. #option ═══ #option This command is used to change the state of all the PPWIZARD options that you might wish to modify within a compile. Other options which are global and can't be modified can be specified on the command line. The command allows you to save and restore the current state as well as update one or more options at a time. Most if not all options allow you to reset to the default value, this can either be a value determined by PPWIZARD or overriden by you with the /option switch. Note that to restore the original values you should use the 'PUSH' and 'POP' options. Note that since you can define options using the /option switch and default switches can be set up in the environment, you can simply override any PPWIZARD defaults you don't like without having to change your source code (or even your command line!). Syntax #1 - Saving + Restoring State [WhiteSpace]#option PUSH | POP This form of the command saves or restores all options controlled by the #option command. This allows you to make the required option changes and restore the original situation if required (for example in a header file). Syntax #2 - Setting An Option [WhiteSpace]#option OptionName[WhiteSpace]=[WhiteSpace]["]NewValue["] ... You may have any number of options specified on one statement. While not shown in the syntax diagram above you can specify "PUSH" any number of times as well. The following options are currently available:  AllowPack  AllowSpell  AtChangeType  CsReplacement  DebugLevel  DefineMacroReplace  ExtraIndent  ExpandX  HashPrefix  KeepIndent  LeaveBlankLines  LineComment  LineContinuation  MacroParmTags  ParmVal  Replace  ReplacementTags  Tabs  Warnings  WhiteSpace You may also wish to have a look at the rexx "OptionGet()" and "OptionSet()" routines. Example #option PUSH ;;Save Current state (we don't need to know what it was - EXCEPT '#' = command prefix!) #define FRED **** <$Fred> ;;Fred will be subsituted here #option ReplacementTags="[]$?" [$Fred] ;;Fred will be substituted here <$Fred> ;;Fred will NOT be subsituted here #option POP ;;Restore original state ═══ 9.30.1. AllowPack ═══ AllowPack=OnOrOff This #option command allows you indicate lines of code which are not allowed to be packed. The default is that packing is allowed. This option can not be used to turn packing on, it simply identifies areas that should not be packed when packing is enabled. Packing can be enabled using the /Pack switch when generating rexx code or when you begin a #DefineRexx block. This command is useful where there are some non-obvious reasons why code should not be packed, for example if a bug in the rexx interpreter causes the code to fail when packed. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO ═══ 9.30.2. AllowSpell ═══ AllowSpell=OnOrOff This #option command allows you indicate lines of code which are or are not allowed to be spell checked. The default is that spelling is allowed. This option would allow you to indicate that spelling should not occur when you generate javascript etc. Note that there are currently some inter related restrictions: 1. You can only turn spell checking on or off for whole lines. 2. This option may not work in a macro depending on your macro. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO ═══ 9.30.3. AtChangeType ═══ AtChangeType=["]ChangeType["] This #option command lets you alter the way #AsIs and #AutoTag commands will perform replacements. The default method is a simple case sensitive replacement of text. Note that this command actually changes the way the #AutoTag stores the change and will only affect the replacement of those changes defined after this option was used. This command allows new alternative search and replace mechanisms to be slotted in without affecting any existing ones (clashing syntax etc). This method was chosen so that PPWIZARD could remain as fast as possible (it is written in rexx and so keeping performance reasonable sometimes takes compromises). The "ChangeType" parameter can be one of the following: 1. "" (blank) This returns to the "default" mode. 2. CaseSensitive The ReplaceString() routine is used. This is PPWIZARD's default mode as it's also the fastest. 3. CaseInsensitive The ReplaceStringCI() routine is used. 4. Fixed The CompareReplaceFixed() routine is used. If you have some fantastic free PURE REXX search and replace code then I can include it as a new PPWIZARD extension if you send me the code! Example 1 #AutoTag "AAAA" "XXXX" ;;Change upper case "AAAA" only (assuming default mode) ;--- Use ReplaceStringCI() --------------- #option PUSH AtChangeType=CaseInsensitive #AutoTag "BBBB" "YyYy" ;;Change "bbbb" in any case #AutoTag "CCCC" "({*})" ;;If "cccc" in any case is found then surround it by brackets ;--- Use CompareReplaceFixed() ----------- #option AtChangeType="FIXED" #AutoTag '@=,1=^HTML^@=,5=+x+' 'REM CS->@$1,*;' ;;Case sensitive compare for "HTML" then "x" #AutoTag '!i@=,1=^HTML^!S@=,-1=+x+' 'REM CI->@$1,*;' ;;Case insensitive comapre for "HTML" + sensitive compare for "x" #AutoTag '!L!i@=,1=^HTML^!S@=,5=+x+' 'REM CI+spaces->@$1,*;' ;;Same as above but ignoring whitespace (leading) #option POP ;;Restore mode (PUSH/POP useful where original mode unknown etc) ═══ 9.30.4. CsReplacement ═══ CsReplacement=OnOrOff This #option command lets you alter the way ppwizard performs macro replacement. By default ppwizard macro names and macro parameter names are case insensitive. This command allows you to specify that case matters. This will give ppwizard more flexability when generating certain languages (such as XML or XHTML). Note that Standard Definitions and rexx variable names are always case insensitive. You will need to be careful how you use this option (if not used early in the piece). Any macros created while this option was off were created in upper case, while any parameters within the definition don't matter until the replacement takes place. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO Example #option CsReplacement=ON #define AAAA 1111 #define aaaa 2222 ;--- Test Macro Replacement --- 1. <$AAAA> ;;Expect "1111" 2. <$aaaa> ;;Expect "2222" 3. <$AAaa> ;;Expect ppwizard to fail here ═══ 9.30.5. DebugLevel ═══ DebugLevel=["]Command1,Command2,...["] This #option command allows you to modify the output generated by /debug and #debug. PPWIZARD generates quite a bit of debug information when debug is on, this is fine for small source files but could easily become hundreds of thousands of lines in more complex situations. If you are debugging a specific issue you may want to turn off debugging of unrelated events (this could also speed things up). Of course being more selective about placement of #debug commands is another very good option (why debug the whole process?). Note that you can turn off almost all debugging output, doing so could make it very difficult to determine what is going on as statements such as #AutoTag could transform lines in what appears to be a magical manner. It's up to you to determine what level you require. The Commands You may specify any numbers of commands, each separated by a comma. A command may begin with a '-' (to turn off) or '+' (turn on - default) the debug facility. By default all debug output is generated. Valid debug facilities are:  ALL This represents all debug options. This less "USER?" is the default situation when PPWIZARD starts.  AFTERREPLACE All display of lines after some sort of replacement such as that by #AsIs commands or your macros.  ASIS Debug the #AsIs command.  AUTOTAG Debug the #AutoTag command.  CONDITIONAL #if, #endif output etc.  DEFINING Output related to defining variables/macros.  EVALUATE This debugs PPWIZARD functions that can be used in #evaluate or #if commands etc.  FOUNDVAR Output to do with individual processing of your macros.  FOUNDVARPARMS Output to do with individual processing of your macro's parameters.  FOUNDSTDVAR Output to do with processing of individual Standard Macros.  IMPORT Debug any IMPORT statements PPWIZARD performs. This will also automatically adjust "MACROVALORDEF".  INTERPRET Debug any INTERPRET statements PPWIZARD performs. PPWIZARD does not trace all but will show ones from #if and #evaluate commands.  MACROVALORDEF PPWIZARD allows some things to be defined via a macro, there is usually a default value. This debugs these situations.  OPTIONS Any output related to #option command.  OPSYS Debug commands executed by operating system.  QUOTING Debug the calls that grab quoted values.  REXXVAR Debug the #RexxVar command.  REXXTRACE Turn on rexx's inbuilt tracing for the execution of any rexx code that gets executed by commands such as #if, #evaluate and #import. This can be quite extensive so you might want to turn it off or lower its level (see below) for general debugging. The format of the output is described below. The PPWIZARD macro "REXXTRACE" can be used to control the level of rexx debugging. The default level is "INTERMEDIATES" with "RESULTS" generating less output while still being useful. The value you specified is used in the rexx "TRACE ???" command. Preceeding the value with '?' (as in "?Results") turns on interactive trace. You can execute any rexx commands to display or modify values.  SPELLING Show all spelling related output?  USER1 & USER2 Nothing in ppwizard itself makes use of these debug states, you can make use these for your own purposes. You can use these two flags either as a number (ranging from 0 to 3) for as 2 options (on or off). To test the current state you need to call IsDebugOn(). The value of USER bit one is 1 and USER bit two is 2. Note that you could define your own debug "flags" using "/define depending on the type of debug. The disadvantage on using these bits is the mimimum extra debug output is the contents of each line as it is processed. REXXTRACE Output This debug output is supplied by the rexx interpreter. The output from Regina is much inferior to that of OS/2 however it's still very useful. For an alternative way of debugging rexx code have a look at the /$Trace switch. The following can be used as a guide to understanding the output:  Every clause traced will be displayed with automatic formatting (indentation) according to its logical depth of nesting and so on, and the results (if requested) are indented an extra two spaces and are enclosed in double quotation marks so that leading and trailing blanks are apparent.  All lines displayed during tracing have a three-character prefix to identify the type of data being traced. The prefixes and their definitions are the following: - *-* Identifies the source of a single clause, that is, the data actually in the program. - +++ Identifies a trace message. This can be the nonzero return code from a command, the prompt message when interactive debug is entered, an indication of a syntax error when in interactive debug, or the traceback clauses after a syntax error in the program. - >>> Identifies the result of an expression (for TRACE R) or the value assigned to a variable during parsing, or the value returned from a subroutine call. - >.> Identifies the value assigned to a placeholder during parsing. - >C> The data traced is the name of a compound variable, traced after substitution and before use, provided that the name had the value of a variable substituted into it. - >F> The data traced is the result of a function call. - >L> The data traced is a literal (string or constant symbol). - >O> The data traced is the result of an operation on two terms. - >P> The data traced is the result of a prefix operation. - >V> The data traced is the contents of a variable. Example Lets turn off all optional debugging except CONDITIONAL and OPTIONS: #option DebugLevel=~-ALL,+CONDITIONAL,OPTIONS~ ═══ 9.30.6. DefineMacroReplace ═══ DefineMacroReplace=OnOrOff This #option command allows you to modify the way #define and #DefineRexx commands are processed. Normally no replacement of any macros within it's parameters are performed. This has its good points (which is why it's the default) but at times you may wish to override this behavior. Apart from anything else in some cases this may speed things up. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO Example #define AAAA ValueAAAAOld #define BBBB <$AAAA> ;;Macro AAAA was not replaced #option DefineMacroReplace=ON ;;When #define command executes replace any references to macros straight away. #define CCCC <$AAAA> ;;Macro AAAA was replaced #define+ AAAA ValueAAAANew ;;Change Value of "AAAA" #option DefineMacroReplace='' ;;Set to the default value ;--- Use macros defined above ----------------------------------------------- <$BBBB> ;;Will generate "ValueAAAANew" <$CCCC> ;;Will generate "ValueAAAAOld" Example - Overcoming PPWIZARD Hang The following is a fragment of a rexx program that supports a number of standard rexx operators (but not all). It is trying to build up a list of valid operators to display if the user chooses an unsupported one. Because of the fact that by default a #define does not replace macros the following example would fail with an infinite loop (if the #option commands were removed). /*--- Now compare --------------------------------------------*/ #define CompRepOperator \ when sr_Operator = '{$Operator}' then %\ srCompRc = sr_bit {$Operator} sr_CompWith; -\ #ifndef CSR_ValidList -\ #define CSR_ValidList {$Operator} -\ #elseif -\ ;--- Careful or this line causes infinite loop --- -\ #define+ CSR_ValidList <$CSR_ValidList>, {$Operator} -\ #endif select /*--- Test for supported compare operators ---------------------------*/ #option PUSH DefineMacroReplace="ON" ;;Used push/pop - Making no assumptions about current state <$CompRepOperator Operator='='> <$CompRepOperator Operator='<>'> <$CompRepOperator Operator='=='> <$CompRepOperator Operator='\=='> #option POP /*--- Not Valid ------------------------------------------------------*/ otherwise Die("Unsupported operator of '" || sr_Operator || "' used", 'ONLY "<$CSR_ValidList>" are valid'); end; ═══ 9.30.7. ExtraIndent ═══ ExtraIndent=["]IndentCmd["] Whenever "KeepIndent" mode is on the current indent value is added to the start of each line. The default extra indent is none. The "IndentCmd" parameter is a rexx command which produces a string value which will be used for extra indenting. Example The following command would increase any indenting by 10 spaces for following lines: #option ExtraIndent=^copies(' ', 10)^ KeepIndent=ON ═══ 9.30.8. ExpandX ═══ ExpandX=["]CompleteList["] Normally codes are only expanded just before the data is written to the file (ie "LATE"). You may wish to vary when the replacement occurs. You can choose "COMMAND" to have replacements occur when a PPWIZARD command's parameters are expanded or "EARLY" to expand early on lines that are not PPWIZARD commands. The CompleteList parameter is a complete list of all the locations you wish expandion to occur on (COMMAND,EARLY,LATE) or "NONE" to completely turn off the expansion or "" to use default state. Example ;--- Turn off all expansion --- #option ExpandX="NONE" ;--- Expand everywhere -------- #option ExpandX="EARLY,LATE,COMMAND" ;--- Just expand early -------- #option ExpandX="EARLY" ═══ 9.30.9. HashPrefix ═══ HashPrefix=["]NewPrefix["] This #option command allows you to modify the characters which tell PPWIZARD that a line contains a ppwizard command. The default is that PPWIZARD commands begin with '#'. The NewPrefix parameter if empty sets the default value or specifies the new character or characters that preceed all commands. This command is useful if the language or file you are processing already uses the '#' character for its own reasons. Rather than using many codes it is much easier to move PPWIZARD out of the way. Example #include "FILE1.IH" #option hashprefix='!' ;;Set prefix to '!' !include "FILE2.IH" !option hashprefix='' ;;Set prefix to default value #include "FILE3.IH" ═══ 9.30.10. KeepIndent ═══ KeepIndent=OnOrOff This #option command lets you determine whether or not leading whitespace is removed from lines that are read from a file. If you wish to keep whitespace you can also use the ExtraIndent option to indent each line if you wish. An alternative to this command is to use "" to create whitespace as required. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO Example #Option keepindent=ON Want Indent on this line As well as this line #Option keepindent=OFF Example - Alternative way The way demonstrated here can make it easier to format your source code so it's easy to read. The following example will generate the same 2 lines as the previous example: Want Indent on this line As well as this line ═══ 9.30.11. LeaveBlankLines ═══ LeaveBlankLines=OnOrOff This #option command lets you determine whether or not blank lines are ignored. By default they are. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO Example #Option LeaveBlankLines=ON ;;Don't drop blank lines ═══ 9.30.12. LineComment ═══ LineComment=["]ASingleChar["] This #option command allows you to specify an alternative character (to ';') for starting comments. If NULL is specified for ASingleChar then comment removal is disabled. An empty value will set it back to the default, otherwise the character becomes the new comment character. The same character doubled up becomes the inline comment indicator. Example ;--- This is a comment --- ;;Make the following text appear bold #option linecomment='@' @@Remove the bold attribute @--- This is a comment --- ;--- This is NO LONGER a comment --- @--- Restore default value (without hard coding it) --- #option linecomment='' @@Better way is to use push/pop ;--- This is a comment (no comments after the following line executed) --- #option linecomment='NULL' ;;Better way is to use push/pop ;--- This IS NOT a comment as comments disabled above -------------------- ═══ 9.30.13. LineContinuation ═══ LineContinuation=["]FullOrPartialSpecification["] This #option command allows you to alter the current Line Continuation characters or indeed turn it off altogether. The "FullOrPartialSpecification" parameter can be one of the following: 1. NULL In this case line continuation is turned off. 2. "" An empty value means use the default value. 3. exactly one character A single character value replaces the meaning of the '\' character. 4. exactly five characters This replaces all special characters used for line continuation as follows: a. Replacement for '\'. b. Replacement for down arrow character. c. Replacement for '-'. d. Replacement for '+'. e. Replacement for space. See the Line Continuation section of this document for more details. Your editor may not like the low ascii down arrow character (or you may hate it!), this option allows you to easily change it to another character of your choice. Example 1 We just wish to change the '\' so that we use '~' instead, so that we would use '-~' etc: #option LineContinuation="~" Example 2 Get rid of the down arrow variation, otherwise stick with defaults: #option LineContinuation="\@-+ " ;;'@\' now used for "newline" continuation Example 3 This example changes the down arrow character to the ASCII character decimal 20, no real reason however it does demonstrate a more complex possibility: #evaluate NewDownArrow 'd2c(20)' #option LineContinuation=%\<$NewDownArrow>-+ ^ ═══ 9.30.14. MacroParmTags ═══ MacroParmTags=["]NewTags["] This #option command is used to control the tags used within a macro definition to specify the location where a parameter replacement occurs. Use with care. You would normally only use once at the start of your code - think about the impact on any existing macros. If an empty parameter is supplied then the default is restored otherwise the parameter must have exactly 3 characters in it. The characters are in order: 1. Replacement for '{'. 2. Replacement for '}'. 3. Replacement for '$'. Example #option MacroParmTags="()%" ;;Parameters now start with '(%' and end with ')' #option MacroParmTags="" ;;Set to default values ═══ 9.30.15. ParmVal ═══ ParmVal=["]Value["] This #option command lets you control the macro parameter validation taking place. Parameter validation is used to ensure that all parameters passed to a macro are used, the reason for this is that if they are not you probably misspelt it! The "Value" parameter can be one of the following: 1. ON This means that parameter validation is always performed. 2. OFF This means that parameter validation is never performed. This turns off any "{$!}" validation you might have. This might be required in some cases where someone has designed some macros for you however your use of this or coding style means that the validation is causing you problems. 3. SOME Only validations indicated by the use of "{$!}" tag are performed.

This is the default state. 4. "" An empty value indicates that the default value for the build should be restored. ═══ 9.30.16. Replace ═══ Replace=OnOrOff This #option command lets you to temporarily suspend replacement of definitions (and symbols). This allows you to pass through some complex lines without having to spend ages working out how you can tag it so as not to expand out (or fail trying). It is recommended that you turn off substitution for as short a time as you require it. Use with care. This command could be very handy if you needed to create a variable with a "#evaluate" command but you didn't want all the variables in the contents replaced straight away. If the "OnOrOff" parameter is empty then it defaults to the current default value, otherwise one of the following is expected:  ON  OFF  YES  NO Example The following is extracted out of a real macro that I had to set up, I was having trouble with '<$endExample>' expanding out when what I really want is the literal text: #Option REPLACE=OFF \ #AutoTag '<$endExample>' '~$endExample>' \ #AutoTag '<' '' \ #AutoTag '#' '#' \ #AutoTag '~$endExample>' '<$endExample>' \ #Option REPLACE=ON \ ═══ 9.30.17. ReplacementTags ═══ ReplacementTags=["]NewTags["] This #option command is used to control the tags that are required to tell PPWIZARD that you wish macro substitution to occur. Use with care. You would normally only use once at the start of your code - think about the impact on any existing macros. If an empty parameter is supplied then the default is used otherwise the parameter must have exactly 4 characters in it. The characters are in order: 1. Replacement for '<'. 2. Replacement for '>'. 3. Replacement for '$'. 4. Replacement for '?'. Example #define FRED **** <$Fred> ;;Fred will be subsituted here #option ReplacementTags="[]$?" [$Fred] ;;Fred will be subsituted here <$Fred> ;;Fred will NOT be subsituted here #option ReplacementTags="" ;;Set to default values ═══ 9.30.18. Tabs ═══ Tabs=["]HowToHandle["] This #option command can be used to adjust the way that PPWIZARD processes tab characters (ascii 9). The "HowToHandle" parameter controls how tabs if found are handled. Valid options are:  Ignore Don't do anything, just ignore, this may cause preprocessor to fail (depending on where tabs are located).  ToSpaces Each tab is converted to one only space.  Warnings Each tab is converted to one only space and a warning is generated. This is the default condition.  A Number This option is useful where your source uses a fixed tab stop (of 8 is very common). Each tab is expanded to the correct number of spaces for the tabs position. ═══ 9.30.19. Warnings ═══ Warnings=["]IgnoreWhich["] This #option command allows you to have control of the handling of individual (or groups of) messages. You can choose to completely ignore particular messages or you can "promote" them into fatal errors. Warnings can come from PPWIZARD, the #warning command or the Warning() function. By default no warnings are ignored or "promoted". The "IgnoreWhich" parameter can be one of the following: 1. NULL No warnings will be ignored or "promoted". 2. "" An empty value means use the default value. 3. All Warnings Listed This should be one or more match specification strings each separated by ';' (use ':' under unix). Each match specification may begin one of the following characters:  '-' This means ignore any warnings that match the specification. As far as you are concerned there is no issue. This is the default action.  '+' This means promote any warnings that match the specification to a fatal error.  '!' This means treat any warnings that match the specification as we'd normally would. This can be used to handle messages that might overwise match a following specification. All messages match "*". It will also match if the text of a warning message contains the specification string (case insensitive check). If a message is dropped then you can still see the message in debug mode as well as the reason it normally gets dropped (that is the specification string it matched). The warning message text which is searched includes the line number as well as the warning ID, basically the exact text that you would normally see so you could prevent warnings down to a particular line number if you wish (although this is not recommended). Warning IDs and text are not documented so you need to wait for one to occur before deciding how to drop it. If you wish to see warning messages but still want a zero return code you should check out the /WarningsRc switch. Example The following example lines show how you can treat any warning message that contains "tabs" (in any case) as a fatal error and completely ignore all other warnings that don't contain "FRED". #option Warnings="+tabs;!FRED;*" ═══ 9.30.20. WhiteSpace ═══ WhiteSpace=["]ExtraWhiteSpaceCharacters["] This #option command can be used to adjust the characters that PPWIZARD treats as whitespace. A space is always treated as whitespace. Each extra character you define will be converted to a real space as lines are read from files. The default whitespace for unix will ensure that PC based files whose lines end with carriage return then linefeed and may have end of file characters embedded in the file can be read without conversion. Example The following example shows how to define the "~" and form feed (hex code '0C') characters as whitespace. In a unix environment we have removed the default whitespace conversions. PPWIZARD INPUT.IT /Option:WhiteSpace="{x0C}~" ═══ 9.31. #output ═══ #output In most situations you would read one or more input files to generate a single output file. There are situations where you'd like more control so that you can generate multiple files. You can nest to any level as only one output file is open at any time so file resources are not wasted. Syntax [WhiteSpace]#output ["]OutputName["] [AsIs] [Append] [NoHeader] [HTML|REXX|OTHER] If "AsIs" was specified then the "OutputName" specifies the name of the output file otherwise the value is passed through the output specification provided with the "/Output" switch. If the "OutputName" parameter is not specified at all then the previous output file is restored. Note that files specified for use "AsIs" do not have their case adjusted as specified on the /FileNames switch, if you require the case to be adjusted you will need to make use of the EnsureFileHasCorrectCase routine. If "Append" was specified then the output file is not deleted if it already exists. If "NoHeader" was specified then if the file would normally have an output header then this is disabled (see /OutHeader). In some circumstances you may wish to generate a new file in a different processing mode to the current one, if this applies to you then choose on of "HTML", "REXX" or "OTHER". When a previous file is restored (no parameters) then new data is appended, otherwise the file is erased before writing the first line. Example Line 1 of file 1 Line 2 of file 1 #output '2nd' Line 1 of file 2 Line 2 of file 2 #output 'c:\path\3nd.ext' AsIs Line 1 of file 3 #output Line 3 of file 2 #output Line 3 of file 1 Example - Relative Filenames The following example show how you can calculate filenames which are relative to the directory where output normally goes (as determined by the /OUTPUT switch: ;--- Macro to calculate filename relative to output directory --------------- #evaluate "" ^OutputDir = EnsureFileHasCorrectCase(_filespec('location', ''))^ ;;Only need to determine once! #define FileRelativeToOutputDir {$File} ;--- Test macro ------------------------------------------------------------- InOutput.OUT = <$FileRelativeToOutputDir FILE="InOutput.OUT"> SubDir\InOutput.OUT = <$FileRelativeToOutputDir FILE="SubDir\InOutput.OUT"> ..\Parents.OUT = <$FileRelativeToOutputDir FILE="..\Parents.OUT"> Example - Dropping output There may be time when you wish to drop some lines, for example you might be processing a file in a number of passes, this shows how you can do this under windows and OS/2: #dependsOn TEMP "NUL" ;;Don't add to dependancy file! #output "NUL" ASIS APPEND ;;Drop output! This line gets dropped #output ;;Stop dropping output! ═══ 9.32. #OutputHold ═══ #OutputHold This command allows you to hold output lines in a buffer rather than writing them directly to the current output file. There are two main reasons why you might wish to do this as follows: 1. You wish to drop a number of lines for some reason (maybe in a macro that makes multiple passes over some data). 2. You wish to modify the data in some way that is not known at the time of output generation. As an example "OL_DOC.DH" when generating the "Next" link at the top of each html page does not know what the next page is (where to link to)! The output is held only for a single output file so that when a new output file is started (with the #Output command) it's output lines are not held. These blocks can't be nested within a single output file! The held output is formatted exactly as it would be if it were not held and had been written to the file, so each line is separated from the next by the currently defined line termination characters (see /CrLf). Syntax [WhiteSpace]#OutputHold [["]MacroContainingCodeName["]] | ["]DROP["]] The command without any parameters indicates the start of the block, and if the single parameter exists then this marks the end of the block. The single parameter is either "DROP" to drop the output or the name of a macro containing rexx code. The held output is held in the "HeldOutput" variable. Example This is a useless example, but does show how it all works: ;--- Define code that modifies the output lines we will hold ---------------- #DefineRexx ModifyHeldLines ;--- Stupid change just as example ------------------------------ HeldOutput = ReplaceString(HeldOutput, "line", "****"); #DefineRexx ;--- The following lines go to the output file ------------------------------ line 1 line 2 line 3 line 4 #OutputHold ;;Start holding output line 5 line 6 line 7 line 8 ;#OutputHold "DROP" ;;Drop lines #OutputHold "ModifyHeldLines" ;;Call rexx code to modify output line 9 line 10 ═══ 9.33. #push ═══ #push This command can be used to save macros or rexx variables onto a stack. This is useful for recursive type applications. Syntax [WhiteSpace]#push ["]Type["] ["]Item["] ... The "Type" parameter is used to indicate what sort of information is being pushed. This should be "MACRO" for macro values or "REXXVAR" for rexx variables. You may specify one or more "Item" parameters. These are pushed (with StackPush()) onto a stack from left to right. Example ;---Set rexx variable and Save --- #RexxVar RxVar = 'Demonstating overlap' #push RexxVar RxVar ;--- Set macros and save value --- #define FirstMacro Something1 #define SecondMacro Something2 #push macro FirstMacro SecondMacro ;--- Restore The rexx variable --- #pop RexxVar RxVar ;--- Change Value --- #define FirstMacro SomethingElse1 ;--- Restore Values --- #pop macro FirstMacro SecondMacro ═══ 9.34. #pop ═══ #pop This command can be used to restore macros or rexx variables from a stack. This is useful for recursive type applications. Syntax [WhiteSpace]#pop ["]Type["] ["]Item["] ... The "Type" parameter is used to indicate what sort of information is being popped. This should be "MACRO" for macro values or "REXXVAR" for rexx variables. You may specify one or more "Item" parameters. These are popped (with StackPop()) off the stack in reverse order (from right to left). The reason for the reverse order is so that you do not have to manually reverse them yourself and possibly making a mistake. Example ;---Set rexx variable and Save --- #RexxVar RxVar = 'Demonstating overlap' #push RexxVar RxVar ;--- Set macros and save value --- #define FirstMacro Something1 #define SecondMacro Something2 #push macro FirstMacro SecondMacro ;--- Restore The rexx variable --- #pop RexxVar RxVar ;--- Change Value --- #define FirstMacro SomethingElse1 ;--- Restore Values --- #pop macro FirstMacro SecondMacro ═══ 9.35. #Require ═══ #Require This is a simple command (Y2000 safe) which checks that the PPWIZARD preprocessor is capable of processing your code. You would probably put this command in a header file that you distribute to users. It will validate that the preprocessor they are using is new enough to handle your header file. Syntax [WhiteSpace]#Require ["]MinVersion["] [["]MaxVersion["]] The "MinVersion" specifies the minimum version number of PPWIZARD. The preprocessing will abort if the preprocessor is too old. The "MaxVersion" would rarely be required or specified. It would be used if the newer version of ppwizard does not handle your older source files and you don't wish to modify them so that it does, in this case I highly recommend specifying the maximum version and commenting the reason so you don't get confused at some later stage. Example #require 98.216 ;;Want PPWIZARD version 98.216 or greater ═══ 9.36. #RexxVar ═══ #RexxVar This command allows you to manipulate rexx variables. You can assign values to rexx variables, save them on a stack or give them the result of simple expressions which can be calculated much faster than with a #evaluate command. Note that you should try to pick unusual rexx variable names otherwise you might overwrite one that PPWIZARD uses. It could cause very strange behaviour. Syntax #1 - Set Up "X" Variable [WhiteSpace]#RexxVar ["]VariableName["] =x= [']ItsValue['] This command allows you to set up "" codes. The "VariableName" parameter is the name of the 'x' variable and can contain virtually any character. The "ItsValue" parameter is the value which the rexx variable is to contain. Unlike the "#evaluate" command the new value is not first interpreted. It is taken as is. In practice I recommend using a quote character such as "^" as it's unlikely to appear in the text, this may make it easier to follow in debug mode etc. This parameter can be a variables name (if unquoted). Syntax #2 - Assign to Rexx Variable [WhiteSpace]#RexxVar ["]VariableName["] = [']ItsValue['] This form of the command lets you assign text directly to a rexx variable. It is very useful in macros as you don't have to worry about quote issues while manipulating the data. For example you would find it very difficult to uppercase some text (probably passed as a macro parameter) if it contained both a single quote and a double quote and in fact how would you know which if any it contained? The "VariableName" parameter is the full name of the rexx variable to be set. The "ItsValue" parameter is the value which the rexx variable is to contain. Unlike the "#evaluate" command the new value is not first interpreted. It is taken as is. In practice I recommend using a quote character such as "^" as it's unlikely to appear in the text, this may make it easier to follow in debug mode etc. This parameter can be a variables name (if unquoted). Syntax #3 - Save/Restore Variable on Stack [WhiteSpace]#RexxVar Operator ["]VariableName1["] ... ;;New Format [WhiteSpace]#RexxVar ["]VariableName["] Operator ;;Old Format The "VariableName" parameter(s) are the names of all variables being pushed or popped (saved or restored). The "Operator" parameter should be one of the following: 1. PUSH, Save rexx variable on stack. 2. POP, get last saved value from stack. For each variable pushed there must be a corresponding pop. It allows you to use the same variable names in multiple places without danger of the value getting modified (say by a #included file). The variable parameters of the pop command are processed in reverse order so that if you have push and pop commands with the more than one variable the variable lists do not need to be reversed by you! Syntax #3 - Simple Variable Manipulation [WhiteSpace]#RexxVar ["]VariableName["] Operator Value2 [SourceValue1] This form of the command lets you perform some simple operations. These will be much faster than performing the same operation using #evaluate. The "VariableName" parameter is the full name of the rexx variable. In this format the variable will be given the result of a simple expression. The value is calculated as follows: VariableName = SourceValue1 {Operator} Value2; The "Operator" parameter should be one of the following: 1. +, Addition. 2. -, Subtraction. 3. *, Multiply. 4. /, Divide. 5. //, Divide, want remainder. 6. %, Divide, want whole number. 7. || Concatenate. The "Value2" is the value which would be added, subtracted etc from the source value. The "SourceValue1" parameter is the the source value. By default the value comes from "VariableName". Both Value2 & SourceValue1 can be one of the following:  A rexx number.  A rexx variable.  A rexx literal. Example The following is sets the rexx variable "MyVar" to the literal "ABC" (as it's quoted): #RexxVar 'MyVar' = /ABC/ The following is sets the rexx variable "MyVar" to the contents of the variable "ABC" (as it's unquoted): #RexxVar 'MyVar' = ABC The following two lines both set the rexx variable "MyVar" to the value 0: #RexxVar 'MyVar' = 0 #RexxVar MyVar = '0' The following is sets the rexx variable "MyVar" to the 3 chars (single quote, space then double quote): #RexxVar 'MyVar' = "' "" Notice that in the above example double quotes are used to contain a value that contains a double quote. This is a common reason for using the "#RexxVar" command when accepting parameters in a macro. The following is one line out of a larger macro, note that we have absolutely no idea what text the parameter may expand to (for example it could easily contain single quotes): #RexxVar 'MyVar' = '{$Text}' The following lines all add one to the "Counter": #RexxVar Counter + 1 ;;Counter = Counter + 1 #RexxVar Counter + 1 Counter ;;Counter = Counter + 1 #RexxVar Counter - "-1" ;;Counter = Counter - -1 A stupid example: #RexxVar Three + 1 2 ;;Three = 2 + 1 The following lines append to the end of the rexx variable "Grow": #RexxVar Grow || ", a string" ;;Grow = Grow || ", a string" #RexxVar Grow || AVariable ;;Grow = Grow || AVariable The following lines could be used in a rexx header file to skip over any subroutines the header contains after all header initialization has taken place: ;--- Initialization --------------------------------------------------------- HeaderVar1 = "Value1"; HeaderVar2 = "Value2"; ;--- Jump around code ------------------------------------------------------- #RexxVar "SkipName" = "SkipSubroutine__" signal ; ;;Jump past functions #RexxVar PUSH "SkipName" ;;Save name of label HeaderFunction1: return('Value'); ;---------------------------------------------------------------------------- ;--- End of code ------------------------------------------------------------ ;---------------------------------------------------------------------------- #RexxVar POP "SkipName" ;;Restore saved value : ;;Create label to mark end of code ═══ 9.37. #transform ═══ #transform This command allows you to define a block of lines for which transformations (that you define) should take place. I got the idea when creating some javascript to output html (using javascript's "document.writeln()" routine), this can be hard as the html code becomes less readable and you have problems with handling quotes. I needed to use javascript to generate HTML controls that should only be available if the javascript they need can also be available. What I wanted was an automated way of adding the "document.writeln()" code and taking care of any content issues such as handling quote characters. This way I just edit the easily readable html code and not worry about which quotes I'm allowed to use or what to do when I need both! A transformation is one of the last things to occur before a line is generated into the output file. To perform transformations you must first define the rexx code to modify the "current" line (in the FileLine variable). An example of code which handles the problem described above follows: #DefineRexx DOC_WRITELN ;--- Escape any escape characters ------------------------------- FileLine = ReplaceString(FileLine, "\", "\\"); ;--- Escape any single quotes (we use this below) --------------- FileLine = ReplaceString(FileLine, "'", "\'"); ;--- Now wrap in javascript code to write it out ---------------- FileLine = "document.writeln('" || FileLine || "')"; #DefineRexx Once you have defined the transformation code you can then mark the start and end of the block of lines that get transformed on output. You can not nest transformation blocks. Syntax [WhiteSpace]#Transform [["]MacroContainingCodeName["]] If the single parameter exists then this marks the start of the block, if missing it marks the end of the block. To start the block you need to supply the name of the macro that contains the transformation code. Example #1 I used this code in some VB Script in a Windows HTA (HTML application) to create "document.writeln" calls automatically and take care of quoting issues: ;--- Define how to convert HTML code into VB "document.writeln()" code ------ #DefineRexx DOC_WRITELN_IN_VB FileLine = ReplaceString(FileLine, '"', '""'); ;;Double up double quote characters FileLine = 'document.writeln("' || FileLine || '")' ;;Wrap in VB code to create the HTML or code #DefineRexx ;--- Create a couple of aliases to hopefully make code self explanatory ----- #define WriteLn \ #Transform DOC_WRITELN_IN_VB #define WriteLnEnd \ #Transform ;############################################################################ sub AddFooter() ; ; Graphics from ; ~~~~~~~~~~~~~ ; http://www.iconbazaar.com/alphabets/animated/great_stars/pg01.html ;############################################################################ #define Bsd \ <$WriteLn>


PRINTQS v<$PGM_VERSION>
<$WriteLnEnd> document.writeln(FormatDateTime(date(), vbLongDate) & " at " & FormatDateTime(time(), vbLongTime)) <$WriteLn>
-\ <$Bsd "B"> -\ <$Bsd "S"> -\ <$Bsd "D"> -\
<$WriteLnEnd> end sub Example #2 This code show another larger chunk of rexx code being used to transform some html: ;--- Turn tracing off (or hugh debug output) -------------------------------- #define REXXTRACE OFF ;--- Define some transformation code ---------------------------------------- #DefineRexx HIDE_HTML ;--- Convert into codes ----------------------------------------- Before = FileLine; After = ''; do Posn = 1 to length(Before) ;--- Get the next byte --------------------------------------- ThisByte = substr(Before, Posn, 1); ;;Byte As Character ;--- Want Hex or Octal codes (Hex is default)? --------------- #ifndef HIDE_HTML_IN_OCTAL ;--- Calculate HEX code ---------------------------------- Code = '\x' || c2x(ThisByte); ;;Byte As Hex code #elseif ;--- Convert to code (octal) ----------------------------- ThisByte = c2d(ThisByte); ;;Byte As ASCII Code = ''; do while ThisByte <> 0 ;--- Add next digit ---------------------------------- Code = Code || (ThisByte // 8); ;--- Prepare for next loop --------------------------- ThisByte = ThisByte % 8; end; ;--- Add escape and put digits in correct order ---------- Code = left(Code, 3, '0'); ;;MUST be 3 digits Code = '\' || reverse(Code); ;;Byte As Octal code #endif ;--- Add to output (note I don't check max literal length!) -- After = After || Code; end; ;--- Now wrap in javascript code to write it out ---------------- FileLine = "document.writeln('" || After || "')"; #DefineRexx ;--- Start HTML ------------------------------------------------------------- ;--- Now create encoded body ------------------------------------------------ ;--- Show something if no javascript ----------------------------------------