═══ 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 works under: 1. OS/2 2. Windows NT 3. Windows 95 4. Windows 3.1 (use DOS) 5. DOS 6. UNIX (tested on Linux) 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. The free "Regina" interpreter is required for operating systems other than OS/2. This preprocessor is commonly used as a 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 preprocessor to use "!if" etc and leave "#if" commands alone if you wish. You may wish to have a look at my HTML/IPF document creation example. This method was used to create both the HTML and IPF versions of the documentation you are now viewing. 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. Its not just easier and fast, it eliminates mistakes. You could set up your source and have automatic checking of the existance 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 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 have different links. The preprocessor could be used in conjunction with a HTML editor however it is most useful for power users. You may wish to check out "http://www.yoursite.co.uk/os/2/webwriter/" as this beta tool has specific support for this preprocessor. 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 effect 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 email (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 I have ported this program to work with the free Regina interpreter (available at "http://www.lightlink.com/hessling"). Do not try to use versions prior to 0.08f. This program was originally written for native OS/2 rexx and this is where most of my testing occurs. My release procedure ensures that when I package up PPWIZARD, it passes the more stingent regina syntax checking and that a small test run generates the same code under OS/2 and Regina. Every so often I test the generation of my web pages under NT and do some other testing under Linux. If you use this program under other operating systems and it fails (or works) then please let me know. If it fails then I will try to resolve it if you are prepared to help (supply info & test). 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). Your Source I have made the preprocessor cross platform. This does not mean that your source will correctly build the output on another platform. There are issues that you will need to take care of to ensure that your code is cross platform also! 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. 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.  You should not use #UnDef on versions of regina prior to "0.08f". Status Under Windows NT No known issues. Status Under Windows 98 People are happily using it under Windows 98. I believe the Windows 98 has the same 3 or 4 year old bug with its command processor as Windows 95. 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. Status Under Windows 3.1 Use DOS version. 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 should be specified using '-' and not '/'. All my testing has been performed on Red Hat Linux 5.1 and 5.2 (using it's default "bash" shell as well as "csh"). You will need to obtain the Regina source code and compile it. All 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. As with all operating systems I am keen to fix any problems, unix is a bigger unknown to me with all it's different shells etc. If you have a problem, please use the "-debug" command line switch and redirect the commands output, along with the name of the shell you are using and any other relevant details. I will typically have a fix for you in a few days and maybe a workaround even faster. 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. ═══ 1.2. Change History ═══ Change History I'm getting quite a bit of feedback now but most simply tells me how happy you all are. While I do lap it all up, I would like more suggestions or bug reports. I don't care how small a bug is (incorrect spelling, incorrectly formatted or difficult to understand error messages). My aim for PPWIZARD to to be very flexible and to work the way you do. If you have to work hard to get PPWIZARD to do what you want then I'd like to know. Most of the changes I have made are due to the fact that as a heavy user of PPWIZARD myself I find situations where PPWIZARD could be modified to make my life easier. Other changes have come about because people have asked me how to do something and I've decided I can make life simpler for everyone! I have a very long list of possible enhancements, your feedback can ensure that something you would like goes to the top of the list! In some cases people have told me what they were doing, this allows me to think about a specific set of circumstances (rather than all possible theoretical ones). After thinking about things a bit I have frequently enhanced PPWIZARD before I was asked (that is I have anticipated my user's requirements). Sometimes I also know something I've done is not perfect, but am waiting for users to indicate a problem area before 'correcting'. 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!  Note that if you require any of the changes mentioned here for the next release then email me and I will either send you a copy or speed up its release. Also if you disagree with a change then tell me why, I can then think about implementing a feature which will do what you want in a better manner (or in worst case senario say "oops" and reverse the change).  Your idea here :-).  2. Version 99.329  PPWIZARD now supports Positional Parameters, these remove the need to "name" parameters.  I have worked out a workaround to regina's annoying "clause length" feature. This has also prompted me to work out a better way of handling rexx code generation (when used as a rexx code preprocessor). If you define your rexx code with #DefineRexx you will never get the clause length message unless an individual line is greater than the "maximum clause length" (1,024 characters in regina interpreters ppwizard supports). Not only that but any rexx code you generate will also not cause clause length problems. Note that regina incorrectly calls a line a clause.  New line continuation code for separate with newline, new default code is "%\" (I should never have used the down arrow...). Using the old code will work for now but generate a warning. At some future stage this support will be removed.  PPWCURL.CMD improved to handle "SSL" links ("https://").  The "{$Parm-}" format no longer exists, it is probably rarely used, if required however (extremely unlikely) you can use the new "$$IGNORE" parameter command.  Some debug mode changes which hopefully make it easier to work through. 3. Version 99.324  Updated '{$?}', can now specify '$$' commands in which case they are applied to each parameter (and they are not in pass through format).  When defining your own '$$' commands you can now determine the source of the value (macro or parameter name).  Updated directory creation code, under regina we can tell if a directory exists, so now only create when required.  New ProcessNext() routine.  New ReplaceMacros() routine.  New /DebugTime switch.  The "BIN2PPW.CMD" updated to work within regina's tight restrictions.  Updated HtmlPre.IH & OL_DOC.DH so that the right angle bracket is now converted to the html code.  Updated error messages when a macro expansion fails, the macro being expanded is now reported. Try to show macro expanded lines where possible.  If compound rexx variable unknown then known "components" are now always dumped.  Some lists and other items would not show up correctly under Internet Explorer, hopefully all occurances have now been fixed. There could be some glitches in the documentation, if you notice problems please report them... 4. Version 99.317  New '$$' command of '$$SPCPLUS'. Adds space before item if its non empty.  If executing #DefineRexx code immediately then macro parameters are always replaced.  New MacroSet() & MacroGet() routines, the later replaces any "GetMacro()" calls which will be removed in a later release.  Updated OL_DOC.DH so that it should now work under regina.  Updated NestChk.H to perform more validation of IDs and created new macro for easy definition of HTML tags you want to verify the nesting of. 5. Version 99.313  Fixed bug in '{$?}', would not always work unless in debug mode!  New "#option" of CsReplacement. By default ppwizard Macros and their parameters are case insensitive.  Updated OL_DOC.DH so that headings can contain single quotes. Also added new as yet undocumented "SimpleList" list type to match IPF "sl" and "esl" tags.  New BulkChangePrepare() routine.  New "" variable which simply tells you if debug is on or off. The new IsDebugOn() call tells you similar information. New "user" DebugLevel states that you can use for your own purposes.  New Debug() and DebugIndent() calls. 6. Version 99.310  The '$$' commands introduced last release now also apply to Standard Definitions, allowing standard variables as well as rexx variables to be easily handled.  The #{ loops can now be used in a macro. Prior to this it would only work if read from file.  The #DefineRexx command can now immediately execute rexx code (no need to save as macro contents).  Document that AddInputFileToDependancyList() and AddOutputFileToDependancyList() can now be used.  Updated OL_DOC.DH so that it no longer generates java navigation (wasn't reliable).  Removed a number of files from main download, now available separately. 7. Version 99.304  New macro and macro parameter replacement options, you can perform translations on whole macro values or on individual parameter values. Tell me if you can think of any other common transformations you would like to be able to do.  New macro replacement option, you can now use '{$?}' to generate "unused" parameters. This will be a very handy feature and allows you to create better macros as replacements to existing HTML tags.  Some rare very early errors were not being correctly reported as they would cause ppwizard to trap. 8. Version 99.299  Updated the #RexxVar command to create better "PUSH" and "POP" commands (old format still supported).  Updated FTPLIKE.IH header so that it can handle filenames and directories that contain single quotes. 9. Version 99.289  There are now some special alternatives to the normal method of macro replacement. Valueless parameters starting with '$$' are now special cases and represent instructions to PPWIZARD.  Updated OL_DOC.DH header, main change is validation of links to ensure that the destination heading exists. Updated it's documentation and fixed some faulty links.  Modified GetImageHeightWidth() so that it now dies on failure instead of generating warnings.  The FTPLIKE.IH header was updated. Added new WPS URL to HTML example.  Input (only) dependencies are now converted to upper case on case insensitive operating systems so that we don't store information for the same file more than once.  Dependency file has a new format. The #DependsOn command has been enhanced so that you can "stamp" commands or files matching masks.  Regina 08h allows better reporting on syntax traps, improved trap handler to take advantage of this change. 10. Version 99.281  New Summary() routine to allow you to add (or remove) details on the displayed summaries.  Updated VALRURL.H to remove "name expected" trap when used under regina.  Updated default whitespace to include EOF (26 decimal) as different versions of regina seem to handle it correctly, then not!  Work around to stream('STATE') & stream('DESCRIPTION') bug in regina 08h beta.  Improved text of some error messages. 11. Version 99.276  Fixed bug in handling of macro parameters which did not have a value (new feature in 99.225). PPWIZARD would fail if the parameter was the last supplied (and there was no spaces after it).  The SortArray() routine has been updated so you can decide whether or not compares are strict. The default is that they are not, strict compares are best for text, numbers however will not correctly sort this way.  Spelling dictionaries are now put into dependency file if required.  Improved way ppwizard fails if user makes certain mistakes with the name of an included file (such as empty name), rexx used to spit the dummy.  New FAQ section in doco.  The HTML generator tags now go in no matter the case of the user html tags. It now also handles a body tag with parameters.  Finally managed to generate a very small test case to demonstrate the 08g "stream('query exists')" bug and sent it to Mark Hessling, he has fixed the problem for the next release. We have also confirmed that this bug has been around for a while. While ppwizard (in my setup) would only fail on 08g, my testcase fails on all regina versions I have access to. For this reason I have decided to support 08g and remove the warning. 12. Version 99.269  Had to restore an old workaround to a regina bug (removed in 99.225). I'd thought it had been fixed (looks like only partially fixed). Quite a few header files updated to correct this. If you had trouble retrieving variables after you'd created them (ppwizard would trap - variable not found) then you were probably bitten by this bug.  The default is now to see each spelling error (for a word) once per build, you can use the new /SpellShowAll switch to indicate that you'd like to see each error.  You can now modify the spelling delimiters from within a dictionary. 13. Version 99.268  Updated #import command so that closing column tags are now generated by default. These are optional but some browsers such as Netscape may not work correctly in all circumstances when they are missing. There are now options which allow the easy definition of text which goes before and after record data (say to change fonts within a cell).  When generating rexx code (/Rexx used) the syntax of the generated code is now checked in all cases. With regina the generated code had previously not been checked.  We now have a basic spell checker, its not perfect and will probably change in future (maybe based on user feedback), but its a good start. It tries to avoid HTML tags and so does not yet handle "ALT" text etc. There are 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.  There are new switches of /SpellCheck and /SpellAddWord. A new option of AllowSpell gives you control over which parts of the output you wish to spell check.  Note that currently ppwizard only reports a spelling related error for a word once per ppwizard invocation not once (or many) per individual build (as it probably should).  HtmlPre.IH & OL_DOC.DH updated so spell checking on examples is optional (default state controlled by user).  The "/DependsOnPpw" switch no longer exists, see the new "/DependsOnComplete" switch.  PPWCURL.CMD improved. New switches allow timed out URLs to be retried and for you to specify if moved URLs are OK or not (for each one). Memory file can be backed up to 'x' levels.  The default handling of the FTPLIKE.IH header should now handle spaces in filenames better. If you have any problems please let me know!  Updated "PPWSORT.H" so default method of sorting is not strict (">>") as this incorrectly sorts numeric values.  Better debug output.  You may need to modify your source, see following issues: a. Updated #import command so that the option "?_BLANK_COLUMN#" now has a underscore before the field number to be consistant with all other options which refer to column #. b. If you use "DecodeUrl()" or "EncodeUrl()" see doco for UrlDecode() & UrlEncode(). 14. Version 99.261  Windows (at least NT) appears to have a bug/feature in its handling of the "dir" command which caused ppwizard to report that no files were found when /ScanSubDir used and maybe other times. I've worked around this bug. This would probably have affected the use of the FTPLIKE.IH header and maybe others.  The way PPWCURL.CMD is invoked has changed, most environment variables have disappeared, replaced by command line switches. Can now test URLs extracted straight from HTML pages. The program is much improved in many other ways.  PPWCURL.CMD will now run under Windows using the windows version of RxSock (although there is no support for FTP checking under windows). Apparently there is a linux version of RxSock with object rexx this may or may not work with regina, please tell me if you try it! 15. Version 99.252  The /Output and /DependsOn switches can now generate their output in a completely separate directory tree (when /ScanSubDir used).  New "" and "" variables.  Updated OL_DOC.DH, main change allows you to specify "targets" on links (section within a html page). Can also save/restore heading levels.  Documented fact that PPWCURL.CMD can be used to check WPS URL objects (created by Netscape etc). Also minor improvements to program.  Assorted performance enhancements.  Started documenting the tags and options of OL_DOC.DH. A few names modified. 16. Version 99.234  Updated #OneLine command so it will correctly handle ppwizard commands embedded within a #define (a macro which executes ppwizard commands).  Updated VALRURL.H and PPWCURL.CMD so that it will now tell you in which html file(s) the failing URL occurs. Assorted other improvements.  New InputComponentLevel() and InputComponentLineLevel() routines. 17. Version 99.230  I've set up an email based PPWIZARD discussion group (using "list bot"). Join up at http://www.labyrinth.net.au/~dbareis/ppwizard.htm.  Please read the changes to the "Bugs or Suggestions" section.  New #OneLine command, hopefully this will please a lot of people (judging by past feedback).  The "PPWCURL.CMD" (URL validator) batch file has had some major improvements, the biggest one being able to specify a period of time (in days) after a successful check before another is required (this is major performance improvement).  Must have forgotten to document the /HtmlGenerator switch. Wasn't working 100% anyway!  Minor change to #import to allow the specification of particular values for each column to replace empty fields (not just "?_BLANK_FIELD" - which still exists). 18. Version 99.225  Can now have macro parameters without you having to specify a value (it will be given the value of the parameter name in upper case). Thanks to feedback from "Mads Orbesen Troest" for this one.  Removed work around to regina value() bug (to speed up PPWIZARD). This bug is fixed in regina 0.08f onwards (the only version that PPWIZARD now supports - see next item!).  Found bug in regina 0.08g (latest available), do NOT use this version, I have reported the problem and am providing as much detail as possible so hopefully the next version will be OK.  A debug message and warning message will be generated if PPWIZARD does not "approve" of the version of regina you are using.  Updated "VALRURL.H" to not do http/ftp support checking if URL checking is not immediate. 19. Version "99.220  The #DefineRexx command now honours the AllowPack setting.  The SortArray() routine is now much faster. Note that the routine now "correctly" uses strict compares, this may have caused "funny" sorts if you had leading/trailing whitespace.  You may need to modify your source, see following issues: a. Updated "PPWSORT.H". Added some easy to use macros for 1 and 2 array sorts. New much faster code is generated, see doco about changes to variable names. 20. Version "99.215  New #DefineRexx command which simplifies the definition of rexx code (for example line continuation characters are no longer required). 21. Version 99.150  New "PPWSORT.H" header. This allows you to define how the sorting is done as well as sort more than one array (keep associated info together).  Updated "VALRURL.H" support. 22. Version 99.148  New Info() routine to match #info command.  Updated "VALRURL.H" header file. Now performs immediate checking of URLs at end of each successful build or can batch URL's for later validation, or you can define your own URL handler.  You may need to modify your source, see following issues: a. "BubbleSort()" renamed to "SortArray()". b. "ReverseIt()" renamed to "ReverseArray()". 23. Version 99.145  New "VALRURL.H" header file which allows validation of remote http and ftp URLs. I am very interested in feedback on this feature.  Updated FTPLIKE.IH.  New "DieIfIoErrorOccurred()" routine which can be called any time prior to the closing of a stream to see if any input or output errors have occurred.  Updated "GetEnv()", it now takes an optional parameter telling it to die if the env var does not exist.  Removed "/CheckImage" & "/CheckHref" validation switches as they did not handle all cases, did not do a really good job of checking, there are better ways of doing it anyway (see the Resource Validation - Local section for more details) and user feedback seems to imply its a rarely used feature. I will probably come up with a new header file and framework for the validation of local files (and maybe remote as well) in a future release.  New "GenerateFileName()" routine which allows you to create filenames from masks exactly like switches such as /Output do. 24. Version 99.135  Assorted linux improvements.  Updated FTPLIKE.IH so it can handle directories in operating systems other than OS/2. It now works well under linux.  Updated NestChk.H to work around bug in regina. Note that under regina 0.08e you will get a "clause" error, please change to "0.08f".  Updated _SysFileTree() to handle directories. Basically also clean up some other "strange" stuff.  #import would fail if you used some import types such as ",,," and your "TMP" or "TEMP" environment variable pointed to a drive without long filename support (PPWIZARD would trap).  If "TMP" or "TEMP" pointed to a root directory (such as in "E:\") then PPWIZARD would trap. A terminating slash on other directories was OK!  Now when a trap occurs variables from nearby lines are dumped to help in problem diagnosis. 25. Version 99.131  In some unusual situations where a file that ppwizard had to locate is read directly from file it could get confused. Under OS/2 this would correctly trap, due to a regina bug/feature it will cause an infinite loop.  Summary information improved. 26. Version 99.120  The way a file is included has been rewritten. A file may now either be read directly from the file or via a memory cache. Reading from cache will improve performance if the file resides on slow media (if it needs to be re-read). If a recursive #include is detected (this is now allowed) then read from cache is forced, there is no more need for a file copy workaround.  A /Inc2Cache switch allows you to override the default read method (file/cache) chosen by PPWIZARD.  Improved CompareReplaceFixed() routine so that it can also be used as a compare function.  No bugs reported or seen however I think in some situations #import could have caused some weird looping or other bugs. 27. Version 99.115  New "#OnExit" command.  Added new _filespec types.  New parameter on GetIdPrepare() call improves functionality in some circumstances.  New ExpandXCodes() call.  New "PUSHPOPM.H" header file which allows you to easily save/restore macro values.  Updated "FTPLIKE.IH" as well as NestChk.H and OL_DOC.DH headers.  Better validation on "#include" and "#output" commands.  Now only generate warning if no lines generated. 28. Version 99.110  New "FTPLIKE.IH" header file which allows you to create simple FTP like listings with ".DIZ" file support. The DIZ file can contain HTML tags.  Fixed bug in "#{" type loops where #if nesting level could get confused if loops were "nested". Possibly other effects. 29. Version 99.106  Improved CompareReplaceFixed() routine.  Now added infinite loop detection (can be turned off) for expansion of macros. 30. Version 99.100  New "#option" of AtChangeType to allow variations on the "normal" case sensitive #AutoTag or #AsIs changes. 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!  New "#option" of ExpandX to provide more control over when codes get expanded.  New ReplaceStringCI() routine to perform case insensitive search and replaces.  New CompareReplaceFixed() routine to perform complex "fixed" type compare and replace operations.  New "" variable.  New TEXTEDIT with PPWIZARD and SHARING HEADERS - HTML + REXX CGI examples. 31. Version 99.092  More of a feature (as code functioned...), however the "StartsMacroParm" and similar stuff was not what I was aiming for! You would only have seen this while debugging T2H imports.  So problems such as the one above can never reoccur, rather than delay trap handling I now use a "simple" trap handler until PPWIZARD has initialized itself enough to use the normal (much more complex) one.  New GetInputFileNameAndLine(), GetFileLineBeingProcessed() & GetLineBeingProcessed() calls so rexx code can keep track of debugging/diagnostic type information.  New "NestChk.H" header file which contains macros for generic handling of nesting validation. You could use this to ensure numbers of "TABLE" tags match numbers of "/TABLE" tags etc (rather than hope testing shows this up).  Now validate #AutoTagState nesting level.  Much more complex import example put into doco. The example reads a comma delimited file (could have been fixed field etc) and generates 3 html files based on the first letter of the surname. 32. Version 99.083  New /WarningsIgnore switch. This allows you to specify one or more individual (expected) messages to ignore.  A parameter on the command line can now be surrounded by double quotes if it needs to contain spaces.  Updated documentation, particularly the #Import command (more details on internal processing etc).  New "Resource Validation - Local" section in documentation.  Documented WriteLineToTmpImportFile() routine, must have forgotten to do so in an earlier release.  New Error() & Warning() routines (useful in filters etc).  Fixed bug which may occur if you had used the ReplacementTags option (rare bug to do with 'x' codes).  Summary now includes warning count (if any).  You may need to modify your source, see following issues: a. The '\\' line continuation form no longer exists (it was an alias for '-\'). You can use the modified (but backwards compatible) LineContinuation option to allow '\\' if you wish. b. Syntax of #Warning slightly modified. To quickly get yourself going simply add "USER " before your warning text. c. If the defined line continuation character ends a line but it otherwise does not look like a line continuation then the line is no longer treated as continued. In practical terms you now need a space before the '\' character! 33. Version 99.074  Enhanced the #Output command so that the new file does not need to be processed in the same mode as the "current" file. For example while generating rexx code you may wish to generate data files (such as TEXTEDIT scripts) which the rexx program will use as input at runtime. This allows #define variables to be easily shared and gives you the option of wrapping everything up in a single source file.  Fixed error message when invalid parameter used on #Output command.  Better temporary file name calculation (and handling) under regina.  Handling of "stderr" redirection changed so should work on "csh" and similar shells under unix and not just the "bash" shell (not 100% sure this was required as regina seems to use "bash" shell for operating system commands).  The "#Import" command can now take "EOF:" in the "Remove" variable to remove to EOF.  Updated "#Import" command so that you can now always specify a number of lines to drop and not just if "CMA-" etc used. Whether or not the '-' is used now just determines the default state.  New /beep switch for people who don't like beeps on errors (grumpy bunch!).  On all operating systems now do "set" command (and capture output) when /debug used. No real reason except may help me in future debugging (help me identify unix shell, version etc).  Other minor debug and doco improvements. 34. Version 99.067  When environment variables containing paths are searched the character separating paths is now ':' for unix, for all other operating systems it remains ';'. Similar change for processing of /#Include switch.  Minor debug and doco improvements. 35. Version 99.056  In unix now default to lines terminating with a newline (no carriage return). Other operating systems now default to CR + LF even for HTML, to 'pack' this more use the /CRLF switch to turn off carriage returns (HTML browsers don't require them). No switches apart from /CRLF modify the line termination state.  New /Exclude switch to allow you to exclude certain files. Now only process a file once even if specified in multiple masks on the same command line.  Improved syntax/novalue trap information on user errors in #if, #evaluate commands etc.  More debug parameters for AddressCmd(), lots of other little debug changes. 36. Version 99.051  New "#option" of WhiteSpace, under unix this defaults to the EOF (decimal 27) and CR (decimal 13) characters. This allows unix to read PC files without problems.  Whitespace after line continuation characters no longer prevents line continuation.  Temporary files under unix will no longer go into the root directory if the "TMP" environment variable is not set up, they will go into the "/tmp" directory (I assume this will always be there).  The /output and /DependsOn switches now have non-wildcard alternatives as placeholders.  Unix has case sensitive filenames, the documentation should now match the correct case of the files.  Other minor changes. 37. Version 99.049  Unix fix for directory search bug. 38. Version 99.048  Improved "TRYME.IT" example to demonstrate more features (while hopefully still being fairly easy to understand).  If all input files end in ".X" and "/Rexx" (or other mode switch) was not specified then /rexx is invoked anyway. Now have a /html switch.  After looking everywhere else for a file PPWIZARD now also checks the directory it is executing from.  Removed "OL_DOC.DH" from document and now bundle together with PPWIZARD.  Minor change to generated rexx header. 39. Version 99.044  New "HtmlPre.IH" header file to make it easier for people to start using PPWIZARD to include example code into a html page.  Many enhancements to ML importing, other import types have also had relatively small changes.  New "Dropped" array during import so you can access fields that are not directly displayed. This would allow you to create combined fields etc.  Fix to /DependsOn when /Template also used.  Minor change to way REXXTRACE define is accessed for tracing rexx code. Improved use of "interactive mode" rexx debugging. 40. Version 99.038  Fixed "#Import" bug where fields could not be reordered with '{2}' etc.  New "#Import" type ML, this allows you to create a text database in an easy to manage format. Some people are already using WRAP imports to handle similar formatted text databases. 41. Version 99.034  Optimised #AsIs text changes so that it will work much better for large numbers of single character replacements such as would be required to convert international characters for correct display in a html browser. New BulkChar2String() routine.  The /output and /DependsOn switches now have a new special character of '?' (allows specification of paths relative to the input file).  Worked out a faster workaround to a regina bug, this should speed up PPWIZARD when the regina interpreter is used.  Major update to the "rexx" section of the manual.  Minor improvement to rexx packing. Minor change to generator header.  Minor cleanups for rexx tracing. 42. Version 99.030  Oops, wildcards were not expanding correctly under regina.  New SortArray() and ReverseArray() "array" routines.  If you were having trouble with the /DependsOn switch then you are probably using regina version 0.08e. It has a bug in the "parse" command which can generate spaces. I have added a workaround but it would be safer to move to a newer version. 43. Version 99.027  Document fact that delimited and fixed imports can be setup so that the format for each record (row of table) can vary depending on the data. This documents a new variable that can be used in a filter.  Enhanced looping so that it can contain "#include" or "#import" commands.  New DebugLevel option of REXXTRACE for debugging any rexx that you might be executing.  Removed "RestrictKey" routine, this functionality can be achieved through the new "GetId" routine. Also see the new "SetId" routine. This is a much more powerful mechanism which "OL_DOC.DH" now uses.  New "" variable.  Minor debug improvements. 44. Version 99.023  New AsIs() and AsIsPrepare() routines.  New AutoTag() routine.  New QuoteIt() routine. 45. Version 99.020  Changed syntax and way "#AsIs" command works so that it is now much more flexible. If you have used the "#AsIs" command you will need to make minor changes. Sorry but I never liked the way it was before... Too limiting.  Changed "#AsIs" mode so that when turned off it restores the state of the options to the state that existed just before the "as is" mode was turned on.  More "#Import" changes/options. You can now filter records in the T2H mode. Largish changes to WRAP import. You can now easily disable or extend on the "standard" #AsIs replacements that occur during import (chars like '<' and the box chars).  New "" & definitions.  New "ToLowerCase" routine.  New "rexx" section in the manual.  Improved summary information. 46. Version 99.014  More "#Import" changes. Default is now to "PROTECT" delimited and fixed imported data. More configurable parameters in T2H import. "T2H" import now finds and by default tags email addresses.  Parm 2 of #AutoTag command now can now include "{$AT}" to refer to the before (automatically tagged) text. This can save a lot of retyping. 47. Version 99.009  Fix looping problem on loops other than the first.  Improved "#Import" type T2H, this affects you if you used "_LINK" definitions.  Modified "#Import" type WRAP, to work better under regina (OS/2 seems to have better garbage collection).  No longer delete temporary files during #Import command if debug mode is on.  Modified "#option" command so push and pop commands can be combined with setting options.  Added an example of importing using SQL.  I correct some code which may not have correctly handled a line with all blanks (when writing to output file).  Note that you can now tell PPWIZARD exactly what characters to translate during the #Import command. For example if your text includes internation characters such as umlauts you could convert them to the html symbols so that they display correctly. 48. Version 99.006  Improved documentation.  Fixed major problems with "#Import" type T2H. 49. Version 99.005  PPWIZARD looping is now possible. Requested by Chris Wenham. Note that you have always been able to do loops in rexx (#evaluate).  New "#Import" type T2H. This is basically a TEXT to HTML conversion mode. It is reasonably configurable (and will get more so). You can determine look and feel and whether "http:" links are made links or not, plus more. Use /Debug to make up for lack of doco for now - everything can be turn off or changed for example you can turn off creation of links and can change mode from "PRE" to blank line indicates end of paragraph. If you know of common examples of text then maybe we can get much smarter. Basically feedback required.  Now when in HTML mode (the default), if no input files were specified PPWIZARD will look for "DEFAULT.IT". Requested by Chris Wenham.  New "" variable. Feedback from Chris Wenham.  New "", "", "", "" and "" variables. 50. Version 99.001  Fix some minor documentation issues.  Generator meta tagging added when generating html. I have still kept the history for previous releases (as far back as 98.044), so if you wish I could send it to you, however if you are interested in stuff this far back take my word for it you are better off with the current release! ═══ 1.3. 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 its 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.3.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 its hard to swap between frequently used configurations. ANSWER There is no need for a separate file as ppwizard can accept anything the command line can accept from environment variables. In most operating systems you can either put your options in "config.sys" or in a batch file that you run for your project. That is, the facility is there, it is just supplied in a different way. 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 CONFIG.SYS 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.3.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.4. Bugs, Problems or Suggestions ═══ Before asking questions, I would appreciate it if you'd ensure that your answer was not in the FAQ or the 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 your 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 email based discussion group, any email sent to ppwizard@listbot.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 emails 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 email 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 email me directly then send it to dbareis@labyrinth.net.au. If I think its appropriate I will "CC" the above discussion group with my response. Please zip attachments, this reduces the size of the email 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.5. 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. It is recommended that you backup your source 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. PPWIZARD.CMD Command Line ═══ PPWIZARD.CMD Command Line PPWIZARD[.CMD] InputMask1 [Options[:parms]] The "InputMask1" can be the name of a single file or a filemask containing the normal wildcard characters "?" & "*". You may specify more than one file or mask and they may appear anywhere on the line however none are processed until after all options). Each source file may include other files such as common header files with your standard definitions. If all input files end in the extension ".X" then the default processing mode is /rexx (normally /html). Options All Options begin with '/' unless running under UNIX where '-' is used instead. Options in the optional environment variable "PPWIZARD_OPTIONS" are processed before any specified on the command line. 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}" - see below). Commonly used options: 1. /CrLf 2. /Debug 3. /DependsOn 4. /Rexx 5. /Pack 6. /Output Validation options: 1. /WarningsIgnore 2. /WarningsOk 3. /SpellCheck 4. /SpellAddWord 5. /SpellShowAll Less commonly used options: 1. /Option 2. /Define 3. /DebugTime 4. /Template 5. /GetEnv 6. /Exclude 7. /Inc2Cache 8. /CGI 9. /DependsOnComplete 10. /FileNames 11. /#Include 12. /Other 13. /Tabs 14. /**/ 15. /FilterInput 16. /FilterOutput 17. /ScanSubDir 18. /Color 19. /Beep 20. /Info 21. /Sleep 22. /Html 23. /HtmlGenerator Note that 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:  {x20} - Space  {x22} - "  {x3C} - <  {x3D} - =  {x3E} - >  {x7C} - |  {x26} - &  {x5B} - [  {x5D} - ]  {x7B} - {  {x7D} - } LONG COMMAND LINES / CONFIGURATION FILES Note that PPWIZARD does not support a separate configuration file. It does not need one, you can use the /GetEnv switch to obtain the same effect. RETURN CODES  A return code of 0 indicates success.  A return code of 1 indicates success (with warnings) and /WarningsOk was not used to turn them off.  Any other value indicates an error occurred. 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.cmd %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 '-'!): ppwizard.cmd 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. ═══ 2.1. /Beep ═══ Switch /Beep[:YesOrNo] This is a PPWIZARD.CMD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable. 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 ═══ 2.2. /CGI ═══ Switch /CGI:LogFile This is a PPWIZARD.CMD command line switch. You can set up your own default switches in the "PPWIZARD_OPTIONS" environment variable. 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.cmd EmailForm.TEM /CrLf /CGI
      ppwizard.cmd EmailForm.TEM /CrLf /CGI:LOGS\LAST.LOG
      ppwizard.cmd EmailForm.TEM /CrLf /CGI:LOGS\?


═══ 2.3. /Color ═══

Switch /Color[:YesOrNo] 

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

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. 


═══ 2.4. /CrLf ═══

Switch /CrLf[:YesOrNo] 

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

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 


═══ 2.5. /Debug ═══

Switch /Debug 

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

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). 

To get the maximum output use the switch as early as possible on the command 
line, if you are getting too much output, there are many filtering options (see 
the DebugLevel option). 

If you wish to report a problem with ppwizard then please use this switch and 
send the output 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 


═══ 2.6. /DebugTime ═══

Switch /DebugTime[:NoOrFormat] 

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

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 prevents this from working correctly at this time. 


═══ 2.7. /Define ═══

Switch /Define:Variable=Contents 

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

This command sets variables (like #define), but from the command line.  You can 
set as many variables as you wish. 

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

EXAMPLE 

Define 2 variables 

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

In your code you could do: 

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


═══ 2.8. /DependsOn ═══

Switch /DependsOn:[-]EditMask 

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

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. 

You can not build a system that can not be reliably tracked however you may 
need to use the #DependsOn command if you directly access files yourself via 
macros. on 

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 {$BASE} 
          This gets replaced with the short filename (less extension) of the 
          current input file.

       2. ? 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 you use the 
          "/ScanSubDir" switch. For example "?OUT\*.HTM".

       3. {$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 the "/ScanSubDir" switch 
          was also used.

 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. 

 EXAMPLE 

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

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


═══ 2.9. /DependsOnComplete ═══

Switch /DependsOnComplete[:YesOrNo] 

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

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. 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 


═══ 2.10. /Exclude ═══

Switch /Exclude:FileMask 

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

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.cmd *.IT /Exclude:TEST*.IT /Exclude:TRY?.IT /Output:OUT\*.html


═══ 2.11. /FileNames ═══

Switch /FileNames:TranslateType 

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

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. 


═══ 2.12. /FilterInput ═══

Switch /FilterInput:RexxCmdFile 

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

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. 
          Its 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') );


═══ 2.13. /FilterOutput ═══

Switch /FilterOutput:RexxCmdFile 

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

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. 
          Its 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') );


═══ 2.14. /GetEnv ═══

Switch /GetEnv:EnvVarName 

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

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. 


═══ 2.15. /HTML ═══

Switch /HTML 

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

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 sets the processing mode for the output file as well as the default 
processing mode for other output files specified with the #Output command. 


═══ 2.16. /HtmlGenerator ═══

Switch /HtmlGenerator:Contents 

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

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. 


═══ 2.17. /Inc2Cache ═══

Switch /Inc2Cache[:YesOrNo] 

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

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. From what I gather Windows (95/98 and NT!) do not have very 
 good memory management. 


═══ 2.18. /Info ═══

Switch /Info[:YesOrNo] 

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

By default important informational messages may be output, these could be 
considered as similar to a warning but no 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 


═══ 2.19. /Other ═══

Switch /Other 

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

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 sets the processing mode for the output file as well as the default 
processing mode for other output files specified with the #Output command. 


═══ 2.20. /Option ═══

Switch /Option:OptionParameters 

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

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. 


═══ 2.21. /Output ═══

Switch /Output:EditMask 

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

This parameter controls how the "InputFile" parameter is transformed to 
generate the correct name for the generated output file. on 

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 {$BASE} 
          This gets replaced with the short filename (less extension) of the 
          current input file.

       2. ? 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 you use the 
          "/ScanSubDir" switch. For example "?OUT\*.HTM".

       3. {$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 the "/ScanSubDir" switch 
          was also used.

 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". 


═══ 2.22. /Pack ═══

Switch /Pack[:YesOrNo] 

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

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). 


═══ 2.23. /Rexx ═══

Switch /Rexx 

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

The input is treated as rexx source.  Rexx comments are removed from the 
source. 

This switch sets the processing mode for the output file as well as the default 
processing mode for other output files specified with the #Output command. 

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. 


═══ 2.24. /SpellAddWord ═══

Switch /SpellAddWord:[-]NameOfAddFile 

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

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 "-". 


═══ 2.25. /SpellCheck ═══

Switch /SpellCheck:NameOfDictionary 

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

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.


═══ 2.26. /SpellShowAll ═══

Switch /SpellShowAll[:YesOrNo] 

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

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 


═══ 2.27. /ScanSubDir ═══

Switch /ScanSubDir 

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

By default this program only checks the directory specified in the "InputMask", 
specify this option if you wish to process subdirectories as well. 


═══ 2.28. /Sleep ═══

Switch /Sleep:NumberOfSeconds 

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

This option can be used to pause execution for a period of time after PPWIZARD 
completes processing normally (no trap etc).  Used with the "/DependsOn" switch 
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. 


═══ 2.29. /Tabs ═══

Switch /Tabs:TabOption 

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

The "TabOption" 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. 


═══ 2.30. /Template ═══

Switch /Template:TemplateFile 

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

Normally PPWIZARD begins by reading from the input file. This switch modifies 
this behavior.  The name of the "input file" is stored in the variable 
"" and the file named on this switch is loaded instead. 

The template file would generally #include or #import the data file. 


═══ 2.31. /WarningsIgnore ═══

Switch /WarningsIgnore[:IgnoreWhich] 

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

This switch allows you to have individual control of which warning messages you 
wish to see. If this switch is used more than once the last used invocation is 
what is used. Warnings can come from PPWIZARD or from the #warning command. 

To turn off ignoring of warning messages you would not pass a parameter. This 
would be useful if you have set up a default where some messages are ignored. 

If you supply a parameter then you can specify one or more strings (each 
separated by ';', or ':' under unix). If the text of a warning message contains 
any of the strings (case insensitive check) then the message will not display 
and the warning return code will not be generated. If a message is dropped then 
you can still see the message in debug mode as well as the reason it normally 
gets dropped. 

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 /WarningsOk switch. 


═══ 2.32. /WarningsOk ═══

Switch /WarningsOk[:YesOrNo] 

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

By default when one or more warnings are displayed a return code of 1 will be 
returned, when this switch is used to indicate that Warnings are OK then a 
"good" return code of zero will be returned instead. 

This switch simply 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 /WarningsIgnore switch. 

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

         Y 
         N 
         YES 
         NO 


═══ 2.33. /**/ ═══

Switch /**/[:YesOrNo] 

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

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 


═══ 2.34. /#Include ═══

Switch /#INCLUDE:FileList] 

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

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.cmd  *.it  /output:out\*.htm /CrLf /#Include:Header1.H;Header2.H


═══ 3. 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. 


═══ 3.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. 


═══ 3.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 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


═══ 3.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 it 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 #OneLine 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^ \ > ═══ 3.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), the only restriction 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. EXAMPLES The following are examples of valid quoted strings:  "A string"  'Another string'  ^A 'string' which contains "quotes"^  █ABC█  NoQuotesRequired ═══ 3.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. EXAMPLES The following are examples of valid quoted strings:  ^A 'string' which contains "quotes"^  "A string with "imbedded" double quotes" ═══ 4. Macros ═══ Macros 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. Macros can be created using one of the following methods: 1. #define[+] 2. #evaluate[+] 3. MacroSet() 4. /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 as in:

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, including the following specialised forms: 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. The following sections provide more details about macros (please read in order): 1. Simplest Macros 2. Using Standard Definitions + Using REXX Logic 3. Multi Line Macros 4. Macros With Mandatory Parameters 5. Macros With Optional Parameters 6. Macro Parameters without values 7. Positional Parameters (not named) 8. Expand All Unused Parameters 9. Special MACRO Replacement "$$" Commands 10. Special MACRO PARAMETER Replacement "$$" Commands 11. Multi Line Macros With Logic 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. ═══ 4.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). ═══ 4.2. 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>')" ═══ 4.3. 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) it breaks it up into multiple lines so that any imbedded PPWIZARD Commands will get executed. ;--- 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. ═══ 4.4. 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@>. ═══ 4.5. 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. ═══ 4.6. 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 ═══ 4.7. 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 comments must start with a double quote (as demonstrated above), a single quote or an equal sign. 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)@> ═══ 4.8. 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 keywords used on a reference except "FILE" and "ALT". If there are specific keywords you don't want included then you should preceed this command with the parameter using '$$IGNORE'. If there were no keywords then nothing is expanded else a space preceeds the resultant keywords. 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. ═══ 4.9. Special MACRO Replacement "$$" Commands ═══ Special MACRO Replacement "$$" Commands 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. 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 and replacement of parameters has occurred. As well as all '$$' commands shown earlier (except the $$PASS ones) these commands are also available:  $$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.  $$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.  $$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.  $$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.  $$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 ""e;".  $$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.  $$UPPER The parameter will be converted to upper case.  $$LOWER The parameter will be converted to lower case.  $$ADDCOMMA The parameter will be formatted using AddCommasToDecimalNumber().  $$? 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. 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>"; ═══ 4.10. Special MACRO PARAMETER Replacement "$$" Commands ═══ Special MACRO PARAMETER Replacement "$$" Commands 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. Within a macro's data, when referring to a parameter you can specify certain special commands (all begin with '$$'). These commands (there can be more than one) occur immediately preceeding the '}' character, available commands are:  $$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).  $$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.  $$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.  $$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.  $$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.  $$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 ""e;".  $$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.  $$UPPER The parameter will be converted to upper case.  $$LOWER The parameter will be converted to lower case.  $$ADDCOMMA The parameter will be formatted using AddCommasToDecimalNumber().  $$? 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. 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'> ═══ 4.11. 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
═══ 5. Rexx ═══ Rexx REXX is a very powerful interpreted programming language. While you don't need to know much about rexx to use PPWIZARD you will find that you can do so much more if you do. There is a lot of 3rd party support for rexx, not only for OS/2 but for windows as well. This program is written in rexx and has specific commands that allow you to embed rexx code. The following situations allow you to execute rexx code (some other minor situations as well): 1. #if commands. 2. #evaluate commands. 3. #import filters. 4. "standard definition". 5. In the CompareReplaceFixed() routine. For OS/2 users an online rexx manual was installed for you (by OS/2 install process). Otherwise you can get a copy of the regina documentation from http://www.lightlink.com/hessling/ There is a DebugLevel option of REXXTRACE that you can turn on or off to control level of debugging output from the rexx commands you execute. Regina's debugging is not as good as OS/2's native debugging but its still a help. The following information provides a very small summary of rexx, for people unfamiliar with programming this may not be enough and you may need to look elsewhere. A good place to ask questions or just sit back and watch is the news group "comp.lang.rexx". Some Examples of Rexx Code Integration Some simple one liners: ;--- Capture some HTML information --- #evaluate ShortNameHtml "_filespec('name', '')" #evaluate ShortNameHtmlLowerCase "ToLowerCase('<$ShortNameHtml>')" ;--- Capture date/time information --- #evaluate DateTime @date('WeekDay') || ' ' || date('Month') || ' ' || substr(date('Sorted'), 7, 2) || ' ' || left(date('Sorted'), 4) || ' at ' || time('Civil')@ More complex example where multi statement rexx is formatted in a very readable manner (using #DefineRexx): #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" ═══ 5.1. Rexx Resources - Tools & Links ═══ Rexx Resources - Tools & Links 1. REXXIO A free rexx extension for Windows and OS/2. Contains File Functions, Directory Functions, Search Functions, Window Functions, Keyboard/Mouse Event Functions, Rexx Functions, Registry Functions, Global Stem Variable Functions, General Functions, Comms Functions Event Functions. http://www.lestec.com.au/freelibrary.htm. 2. REGUTIL A free rexx extension for unix and windows. It provides access to windows registry as well as some other powerful file and directory features. It was created by Patrick McPhee and is available from http://www.interlog.com/~ptjm/. 3. RexxSQL - SQL ACCESS Another free product for a large range of operating systems. Support covers a very large number of different databases. It is available from http://www.lightlink.com/hessling/. 4. Rexx Tips and Tricks Absolutely a must read for anyone using rexx under OS/2, only available as an OS/2 INF file. Note that a lot of the information is also applicable to other operating systems. You can get it from http://www.cfsrexx.com/pub/welcome.htm#rxtt. 5. Rexx Language Organisation Links to rexx sites and other interested info, available at http://www.rexxla.org/ 6. TCP-IP (RxSock) Tutorial A good short tutorial on using sockets (URL checking etc) is available at http://www2.hursley.ibm.com/rexxtut/socktut1.htm 7. RxSock For Windows Get a windows version of the RxSock.DLL from http://home.hiwaay.net/~abbott/regina/ ═══ 5.2. Rexx Variables ═══ Rexx Variables Rexx unlike many other programming languages does not require its variables to be predefined and there is only one type (string). A number is just a string of characters. Variable names can be any reasonable length and can contain the letters 'A' to 'Z', the digits '0' to '9' or any of "!?_" (digits can't start a variable name). In PPWIZARD you must not try to use the value of a variable which does not exist or it will trap with a "NOVALUE" abort and output diagnostic information which should spell out your problem. I very much recommend that you don't use simple rexx variable names such as "Count". This is dangerous as it may clash with PPWIZARD variables. If this occurs it will probably be very difficult to diagnose and PPWIZARD (and your code) will probably malfunction in unpredictable ways. No PPWIZARD variables start with '_' and for this reason I recommend that you preceed all variable names with this character. For example instead of 'Count' use '_Count'. All rexx variables you define are global, as are those used by PPWIZARD. This gives a lot of its power but it can also be dangerous. Always try to be aware of this fact. You also need to be aware that PPWIZARD may modify the rexx RC or RESULT variables that you believe has been set by an #evaluate command. Do not rely on these variables, set your own (of course within a single #evaluate PPWIZARD will not touch these variables). Some examples of giving rexx variables a value: #evaluate ^^ ^_Count = 1^ ;;Both this and next line set value to the number 1 #evaluate ^^ ^_Count = '1'^ #evaluate ^^ ^_Count = _Count + 1^ ;;Increase value by 1 #evaluate ^^ ^_Array.1 = 'a value'^ #evaluate ^^ ^_Fred = "a value"^ ═══ 5.3. Rexx Expressions ═══ Rexx Expressions The following operators can be used:  + Adds values.  - Subtracts values.  * Multiplies values.  / Divides values (5/2 => 2.5).  % Divides values, want whole number (5/2 => 2).  // Divides values, want remainder (5//2 => 1). Expressions can also make use of PPWIZARD or standard rexx functions. Some examples of expressions being used: #evaluate ^^ ^ResultOfExpression = (10 + 8) / 2^ ;;Value 9 #evaluate ^^ ^ResultOfExpression = (_Count - 1) % $Div^ #evaluate ^^ ^Path = GetEnv('PATH')^ ═══ 5.4. Rexx Conditional Logic ═══ Rexx Conditional Logic The #if command allows you to evaluate any rexx conditional expression to determine whether its true or not. The following tests operators are concidered to be "non-strict" (leading and trailing blanks are ignored as are leading zeros on numbers):  = Tests if values are equal.  <> Tests if values are not equal.  < Tests if left value is less than the right value (can be text or number).  <= Tests if left value is less than or equal to the right value (can be text or number).  > Tests if left value is greater than the right value (can be text or number).  >= Tests if left value is greater than or equal to the right value (can be text or number). The following tests operators are concidered to be "strict":  == Tests if values are equal.  \== Tests if values are not equal.  << Tests if left value is less than the right value (can be text or number).  <<= Tests if left value is less than or equal to the right value (can be text or number).  >> Tests if left value is greater than the right value (can be text or number).  >>= Tests if left value is greater than or equal to the right value (can be text or number). The following logical operators are also useful:  & - AND (both must be true)  | - OR (either can be true) Some examples follow: #if lines(<$LanguageFile>) = 0 #if Defined('Var1') = 'Y' | Defined('Var2') = 'Y' #if <$TmpHH> < 12 #if translate(GetEnv("PRJSRCDIR")) = "E:\DB\PROJECTS\HOMEPAGE" ═══ 5.5. Rexx Looping ═══ Rexx Looping Loops are one of the complex areas of rexx and most things you will wish to do with PPWIZARD will either not require them or the simpler PPWIZARD loops will be enough. The syntax of rexx loops is as follows: DO [ symbol=start [TO finish] ] [WHILE expression_w] [ [BY step ] ] [ [FOR count ] ] [UNTIL expression_u] [ expression_c ] [FOREVER ] Examples follow (these would need to be integrated with PPWIZARD using the #evaluate command : do 10 /* Do something 10 times */ end do _Count = 1 to 100 /* Do something 100 times (Count given values 1,2,3 to 100) */ end do _Multiple = 0 to 20 by 2.3 /* Loop with _Multiple = all multiples of 2.3 not more than 20 */ end do _Multiple = 0 for 6 by 5.7 /* Loop with _Multiple = the first six multiples of 5.7 */ end _Finished = 'N' do while _Finished = 'N' /* Set _Finished variable to 'Y' to exit loop */ end; do until _Finished = 'Y' & _Fred <> 0 /* Set _Finished variable to 'Y' to exit loop (_Fred must also be non zero) */ end; do 3 until _Answer = "YES" /* Exits loop after 3 times or if _Answer becomes 'YES' */ end do _Count = 1 to 10 until Fred == "" /* Loop 1 to 10 unless condition met */ end do _Count = 1 to 10 /* Looping 1 to 10 */ /* Want to restart loop (don't execute following loop code)? */ if _Restart = 'Y' then iterate; /* Go back to start of loop (_Count incremented) */ /* Want to exit loop early? */ if _Flag = 'Y' | _State = 'R' then break; /* Exit loop */ end ═══ 5.6. Rexx Parsing ═══ Rexx Parsing Parsing is another of rexx's complex areas, a subset of its syntax is summarised here: PARSE [UPPER] LINEIN [template] PARSE [UPPER] NUMERIC template PARSE [UPPER] VAR symbol template PARSE [UPPER] VALUE expression WITH template template -> [firstPosition] assignments [assignments] assignments -> [nextPosition] varlist [stopPosition] varlist -> varname ' ' [varlist] varname -> "non-constant symbol" | '.' firstPosition -> position nextPosition -> position [nextPosition] stopPosition -> position position -> searchPosition | absPosition | relPosition | '(' "expression" ')' searchPosition -> "string constant" absPosition -> "integer" | '=' numexpr relPosition -> '+' numexpr | '-' numexpr numexpr -> "integer" | '(' "integer expression" ')' This is an example of extracting each directory (one at a time) from the path (located in DOS or OS/2 environment): ;--- Get "PATH" from environment #evaluate ^^ ^_Path = GetEnv('PATH')^ ;--- Start list -----------------

The path is:

    ;--- List Components ------------ #{ ;--- Get next directory name - #evaluate ^^ ^parse var _Path _ThisBit ';' _Path^ ;--- Exit if at end of path -- #if _ThisBit = '' & _Path='' #break #endif ;--- Output directory name ---
  1. #} ;--- End list -------------------
═══ 5.7. Standard Rexx Routines ═══ SUMMARY OF REXX "BUILT IN" ROUTINES Note that some of the routines listed below may not be available in the rexx version you are using (neither does it list all functions): ABBREV(information,info[,length]) - check for valid abbreviations ABS(number) - return the absolute value B2D(binary) B2X(binary) D2B(decimal) C2X(string) C2D(string[,n]) D2C(decimal[,n]) - convert between data formats D2X(decimal[,n]) X2B(hex) X2C(hex) X2D(hex) CENTER(s,n[,pad]) - centre a string in a field CENTRE(s,n[,pad]) COMPARE(s1,s2[,pad]) - compare two strings COPIES(s,n) - replicate a string DATATYPE(string[,type]) - test datatype. Type can be: A (alphanumeric) B (bits) L (lowercase) M (mixed case) N (number) S (symbol chars) U (upper case) W (whole number) X (hex) DATE([format]) - get date. Format can be: B (base date - days since 1/1/1 AD) C (days in century) D (days in year) E (European) J (Julian) M (month name) N (normal: dd Mon yyyy) O (ordered) S (sorted) U (USA) W (day of week) FORMAT(number [,[before] [,[after] [,[expp] [,expt]]]] ) - format a number as specified FUZZ() - NUMERIC FUZZ setting INSERT(new,target[,[n][,[length][,pad]]]) - insert new string into target JUSTIFY(s,n[,pad]) - justify text to given width LASTPOS(needle,haystack[,start]) - find last occurrence of a string LEFT(string,num[,pad]) - return an initial substring LENGTH(string) - find the length of a string MAX(number[,number...]) - find the maximum of a set MIN(number[,number...]) - find the minimum of a set OVERLAY(new,target[,[n][,[length][,pad]]]) - overlay new string on to target POS(needle,haystack[,start]) - find the first occurance of a string RANDOM([min][,[max][,seed]]) - return a random number REVERSE(string) - find the reverse of a string RIGHT(string,num[,pad]) - return a final substring SPACE(s[,[n][,pad]]) - evenly space words in a sentence STRIP(string[,[opt][,char]]) - remove leading/trailing spaces SUBSTR(string,n[,length[,pad]]) - return a substring SUBWORD(string,n[,k]) - return a substring of words SYMBOL(name) - test to see if a symbol is defined TIME([format]) - get the time. Format can be: C (civil time) N (normal) L (long) H (hours since midnight) M (minutes since midnight) S (seconds since midnight) E (elapsed time) R (elapsed time then reset) TRANSLATE(string[,[tableo][,[tablei][,pad]]]) - translate characters using given tables TRUNC(number[,n]) - truncate floating point number VALUE(s[,[newvalue][,selector]]) - get or set value of a symbol VERIFY(string,reference[,[option][,start]]) - verify string for valid characters WORD(string,n) - return a word from a string WORDINDEX(string,n) - return the position of a word in a string WORDLENGTH(string,n) - return the length of a word in a string WORDPOS(phrase,string[,start]) - find a phrase in a string WORDS(string) - return the number of words in a string XRANGE([a[,b]]) - return a range of characters Some rexx interpreters support functions which are not ANSI standard, others won't support all standard ANSI routines. If you care about operating system portability you will be careful about which routines you use. PPWIZARD has its own routines which may be be used, these should be used in preference to "standard" rexx ones as they will work in all operating systems that PPWIZARD supports. ═══ 5.8. Rexx Fragments - Kick Start ═══ Rexx Fragments - Kick Start This section will show you some small portions of rexx code (not complete) which can be used to quickly get you up to speed in rexx. Note that the examples below are isolated fragments, you could not cut and paste them and run them though PPWIZARD as they are... ;--- Assign a value to a variable --- SomeVariable = 'the cat sat on the mat'; ;--- Convert string to upper case --- UpperCaseString = translate(SomeVariable); ;--- Get first 2 characters of string --- Left2 = left('abcd', 2); ;--- Get last 2 characters of string --- Right2 = right('abcd', 2); ;--- Get middle 2 characters of string (first char at posn 1) --- Middle2 = substr('abcd', 2, 2); ;;Last '2' is length ;--- See if first char of string is 'A' (either case) --- if translate(left(UpperCaseString, 1)) = 'A' then do; ;--- Any number of rexx statements --- end; ;--- Does "SomeVariable" contain the characters "Fred"? --- if pos('Fred', SomeVariable) <> 0 then ;Does var SingleStatement; else do ;--- Any number of rexx statements --- end; ;--- Is the second word of "SomeVariable" the word "the"? --- if word(SomeVariable, 2) = 'the' then SingleStatement; ═══ 5.9. Rexx Extensions ═══ Rexx Extensions Any of these PPWIZARD routines may be used by your rexx code:  AddCommasToDecimalNumber()  AddInputFileToDependancyList()  AddOutputFileToDependancyList()  AddressCmd()  AsIs()  AsIsPrepare()  AutoTag()  BaseDate()  BreakAt()  BulkChar2String()  BulkChangePrepare()  CompareReplaceFixed()  DataGet()  DataSave()  Debug()  DebugIndent()  Defined()  DieIfIoErrorOccurred()  EnsureFileHasCorrectCase()  Error()  ExpandXCodes()  GenerateFileName()  GetAmPmTime()  GetEnv()  GetFileLineBeingProcessed()  GetFileTimeStamp()  GetId()  GetIdPrepare()  GetImageHeightWidth()  GetInputFileNameAndLine()  GetLineBeingProcessed()  Info()  InputComponentLevel()  InputComponentLineLevel()  IsDebugOn()  MacroGet()  MacroSet()  PadString()  ProcessNext()  QuoteIt()  ReplaceMacros()  ReplaceString()  ReplaceStringCI()  ReverseArray()  SetEnv()  SetId()  SortArray()  Summary()  ToLowerCase()  UrlDecode()  UrlEncode()  Warning()  WriteLineToTmpImportFile()  RexGetTmpFileName()  _filespec()  _SysFileDelete()  _SysFileTree()  _SysSearchPath() ═══ 5.9.1. AddCommasToDecimalNumber() ═══ AddCommasToDecimalNumber() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter (a decimal integer) and adds commas as required. ═══ 5.9.2. AddInputFileToDependancyList() ═══ AddInputFileToDependancyList() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function allows you to specify an input dependancy. The function should be called before the file is read for the most accurate result in all circumstances. This routine is an alternative to the "#DependsOn" command. ═══ 5.9.3. AddOutputFileToDependancyList() ═══ AddOutputFileToDependancyList() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function allows you to specify an output dependancy. The function should be called after you have completed all updating of the file. This routine is an alternative to the "#DependsOn" command. ═══ 5.9.4. AddressCmd() ═══ AddressCmd() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine will pass the command that you specify to the operating system's command processor. The command will by default by logged when debug is on. This is a major reason why you should use this call. If your command produces some files as output or you create some by redirection you can specify the names of the files as parameter 2 onwards and these will be dumped when debug is on Under OS/2 if the command to be executed is a rexx batch file you should preceed the command with "CMD.EXE /c" or the command will fail. If you don't know what the command is you should preceed all commands with that string to play safe. Stupid Example This example shows a directory commands output going into one file and any error messages into another. If debug is on the contents of both files as well as the return code will be dumped. #evaluate "" ^call AddressCmd "dir /od >dirlist.out 2>error.out", "dirlist.out", "error.out"^ ═══ 5.9.5. AsIs() ═══ AsIs() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter and will return the string after all "as is" conversion has taken place (see the #AsIs command). Note that this replacement occurs whether or not "as is" mode is currently on, the AsIsPrepare() function can be called to set up exactly what you wish modified. Note that you may not wish to use this routine because of interference you might cause with the use of the #AsIs command, in this case you might find BulkChar2String() useful. This routine is useful where you are reading in data directly rather than using #include or #import commands. You could be using the rexx linein() routine or accessing SQL data. Stupid Example ;--- Setup INTERNATIONAL symbols (2 only for this demo) --- #AutoTagState + #AutoTag 'Д' 'ä' #AutoTag 'Й' 'ë' ;;Only 2 for this example #AsIs SETUP INTERNATIONAL_SYMBOLS #AutoTagState - ;--- Prepare ASIS Tagging ---------------------------- #evaluate "" ^AsIsPrepare("INTERNATIONAL_SYMBOLS")^ ;--- Assign to some variables ------------------------ #evaluate "NoChanges" ^"Й Й Й"^ #evaluate "Changesmade" ^AsIs("Й Й Й")^ ;--- Generate couple of lines ------------------------ BEFORE: <$NoChanges> AFTER : <$Changesmade> ═══ 5.9.6. AsIsPrepare() ═══ AsIsPrepare() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter made up zero or more "names" previous setup with the "SETUP" command of #AsIs. It basically identifies the tagging you wish to have take place when the AsIs() routine is called. ═══ 5.9.7. AutoTag() ═══ AutoTag() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter and will return the string after all currently defined #AutoTag replacements have been make. Note that this replacement occurs whether or not "auto tag" mode is currently on. This routine is useful where you are reading in data directly rather than using #include or #import commands. You could be using the rexx linein() routine or accessing SQL data. Stupid Example #AutoTagState + #AutoTag 'FROM' 'TO' #evaluate 'Result' AutoTag('from / FROM'); <$Result> ;;Output saved result. #AutoTagState - ═══ 5.9.8. BaseDate() ═══ BaseDate() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to work out a basedate (julian day) given a date. The integer will be negative if an error occurred. You can tell how many days apart 2 dates are by subtraction of one from the other. The basedate is the number of days since 1 January 0001. If the returned basedate integer is divided by 7, the remainder will tell you what day of the week it is (where 0=Monday, 6=Sunday). The number returned for a date is compatible with rexx's "date('BaseDate')" call. INPUT DATE The routine takes a single parameter (the date) with the year, month and day of month being supplied in that order. The year should either be supplied as 4 digits or will pivot at 1980. It will take the input in these formats: 1. YYYYMMDD - any following characters ignored. 2. YY/MM/DD or YYYY/MM/DD 3. YY-MM-DD or YYYY-MM-DD 4. YY MM DD or YYYY MM DD 5. If nothing passed (or blank) then todays date is used. Note that it actually does not matter how many digits are supplied for day of month and month, however a resonable amount of validation occurs. EXAMPLE INPUT DATES 1. date('Sorted'); 2. date('Ordered'); 3. "98-2-12" 4. "1998/02/01" 5. "20001230" 6. "20001230235959" ═══ 5.9.9. BreakAt() ═══ BreakAt() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function gets passed a string and ensures that no component is larger than a value you specify. It is useful for automatically breaking up long URLs in tables etc so a column does not get too wide. The function takes the following parameters: 1. Break Length There are 2 formats for this value:  A single integer specifies the maximum width of each component. The minimum is a third of this value.  You can supply both the minimum & maximum values by separating them with "-" (as in "5-40"). 2. String This is the string we are adjusting. 3. Break At Char List This is a list of chars. We will try and find the longest string less than or equal to "Break Length" that breaks after one of these specified characters, if we can't find one the string is just truncated at the maximum length. If this optional value is not specified then "./:#" is used. 4. Break With Character This specifies the string used to break the string. If this optional value is not specified then "
" is used. The resultant string is returned. EXAMPLE This example shows a table where the first column contains a URL as a hypertext link to the URL shown. We don't wish the column to be wider than 18 characters (longer URLs will span multiple lines). ;--- Define a macro to (1) Create link (2) split up long URLS --- #define LinkToDisplayedURL \ #evaluate "TmpResult" @BreakAt(18, '{$URL}')@ \ \ <$TmpResult> \ #undef TmpResult ;--- Example of use in a table ----------------------------------
;------------------------------------------------------------ ;------------------------------------------------------------
http:// Information
<$LinkToDisplayedURL URL="www.geocities.com/SiliconValley/Heights/6121/"> Programmer's Info Page.
═══ 5.9.10. BulkChar2String() ═══ BulkChar2String() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to convert a whole series of single characters into strings. To convert single characters to other single characters you would of course use the rexx translate() routine. This function takes 2 parameters as follows: 1. The name of the source string. 2. The name of a rexx variable which lists each of the characters (in order) which you wish to convert. For each character in this string an element in the array of the same name contains what it should be converted to. The BulkChangePrepare() routine can be used to simplify the creation of the change information. The routine returns the possibly modified source string. When this routine returns the rexx variable ReplaceCount will have been incremented by the number of replacements made. Silly Example ;--- Set up the conversion information ------ #DefineRexx "" call BulkChangePrepare "Conv"; ;;Initialize to empty call BulkChangePrepare "Conv", '&', '&'; call BulkChangePrepare "Conv", '<', '<'; call BulkChangePrepare "Conv", '>', '>'; #DefineRexx ;--- Modify the input string ----------------- #evaluate '' ^say 'MODIFIED = ' || BulkChar2String('AAAA <&> BBBB', 'Conv')^ ═══ 5.9.11. BulkChangePrepare() ═══ BulkChangePrepare() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to prepare the information required by the BulkChar2String() routine. This function takes 1 or 3 parameters as follows: 1. The name of a rexx variable which you will use in the change call. 2. The character to be replaced. 3. The string that will replace the character. To initialize the change information this routine should be called with out the second and third parameters. This routine does not return anything. ═══ 5.9.12. CompareReplaceFixed() ═══ CompareReplaceFixed() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function has 2 main operations as follows: 1. Compare a string against a compare specification. The return specification parameter is not passed by the caller. Returns 0 if not matched and 1 if match. 2. Compare a string against a compare specification. Either return the original string on no match or a new string as specified by the return specification. This is quite a complicated routine and hopefully the examples will clarify things. This routine can be very useful in #AsIs and #AutoTag processing. The function takes 3 parameters as follows: 1. The string to be compared with. 2. The COMPARE specification. This is made up of one or more of the following command sequences (in any order):  @Operator,Posn=^CmpText^ The "operator" is a rexx compare operator such as "=" or "<>". The "posn" is the integer position of the substring within the "COMPARE" parameter to compare with "CmpText". If the value is positive then the value refers to a position from the left else it refers to a position from the right. For example "2" indicates the second character from the left while "-2" indicates the second last character. The length of the substring is the same as the length of "CmpText". Any character can be used for a quote character around the "CmpText".  ?Operator/CmpText/ The operator should be either "=" or "!". If "=" then we expect to find "CmpText" in the first parameter, otherwise we don't. Any character can be used for a quote character around the "CmpText".  !SubCommand The subcommand is one of: - S The following compares are to be case sensitive (each time this routine is called it begins in case sensitive mode). - i The following compares are to be case insensitive (you should supply upper case "CmpText" text). - I Ignore leading and trailing whitespace. Convert multiple spaces into a single space. - B Ignore leading and trailing whitespace. - L Ignore leading whitespace. - T Ignore trailing whitespace. 3. The RETURN specification. If not supplied then we are doing a simple compare operation and returning 1 on match and 0 if not. This parameter determines what string this routine will return. You can extract parts of the first parameter and intermix text of your own. A return command is imbedded in text and begins with the '@' character, the following byte determines the type of command, valid commands are:  @ A '@@' indicates that the user wishes a single '@'. This is an escape sequence which allows the '@' character to be specified.  $Posn,Len; You wish to extract a string out of the first parameter. You need to specify its position and length. You may supply '*' for the length to indicate that the rest of the string is desired. If the value is positive then the value refers to a position from the left else it refers to a position from the right. For example "2" indicates the second character from the left while "-2" indicates the second last character.  =/RexxExpression/ A rexx expression is executed to determine the text to be used, you have access to the first parameter of this routine in the variable "CompareString". This method should be avoided where ever possible as it is significantly slower. Any character can be used for a quote character around the "RexxExpression" parameter. While some validation of the parameters is performed you should be careful with the parameters passed. If invalid parameters are passed you probably will not get the "change" you desire and I'm not ruling out a PPWIZARD trap. Validations are only performed when they will not (greatly) affect performance. Example - Compare Specifications 1. @=,1=^HTML^ To see if a string starts with the characters "HTML" (in that case). 2. @=,1=^HTML^!i@=,-2=^YZ^ To see if a string starts with the characters "HTML" (in that case) and ends with the characters "YZ" (in any case). 3. !B@=,1=^HTML^!i@=,-2=^YZ^ Same as above but leading and trailing whitespace is ignored. 4. @=,1=/HTML/!i@<>,-2=\YZ\ To see if a string starts with the characters "HTML" (in that case) and does not end with the characters "YZ" (in any case). 5. !i?=/HTML/ We expect the compare string to contain "HTML" (in any case). Example - Return Specifications 1. ABCD Return the string "ABCD". 2. AB@@C@@D Return the string "AB@C@D". 3. REM @$1,*; Return the compare string (first parameter) preceeded by "REM ". 4. REM @$1,1;@$3,1;@$-1,1; Return the 1st and 3rd and last characters of the compare string preceeded by "REM ". 5. REM (@=/strip(CompareString)/) Return the line stripped of leading and trailing whitespace surrounded by round brackets and preceeded by "REM ". Stupid Examples ;--- The following compare operation will return "1" as the compare "matches" --- #evaluate ^^ ^say 'Expect to see 1 ==> ' || CompareReplaceFixed('HTML', '@=,1=~HTML~')^ ;--- The following compare matches and the return specification is processed --- #evaluate ^^ ^say 'Expect to see ASDF ==> ' || CompareReplaceFixed('HTML', '@=,1=~HTML~', 'ASDF')^ ═══ 5.9.13. DataGet() ═══ DataGet() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to retrieve a value previously stored away with the DataSave() function. It is OK for the value not to exist, if this is the case the "default" value you specified will be returned. If you wish you can make the "default" value some sort of "invalid value" to detect what you consider to be an error. The function takes 3 parameters as follows: 1. The Application Key. 2. The Key. 3. The default value (optional, default is ''). ═══ 5.9.14. Debug() ═══ Debug() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to output a debug line. The line is only output if debug mode is currently on. The DebugIndent() call can be used to make your output easier to understand. The function takes a single parameter and that is the line to be output. ═══ 5.9.15. DebugIndent() ═══ DebugIndent() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is passed a single numeric parameter which is positive or negative (normally -1 or 1). A postive value causes a bigger indent on the left of Debug() output. If you increase the indent you should remember to decrease it when finished. ═══ 5.9.16. DataSave() ═══ DataSave() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to save a value away using a 2 part key. If you wish you can make the first part constant. The value can be retrieved using the DataGet() function. The function takes 3 parameters as follows: 1. The Application Key. 2. The Key. 3. The data to store. Note that there is no information returned by this function. WARNING Currently the value you save is kept between compiles, this is not the aim and will be corrected in a future release. Do not code anything that relies on this fact. If you use this routine you will need to consider if you can compile more than one source at a time. ═══ 5.9.17. Defined() ═══ Defined() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called (probably in a #if command) to determine if a variable has been defined with either #define or #evaluate. The return code is either 'N' or 'Y'. You would use this routine in a #if command rather than a #ifdef or #ifndef if you want to do something which involves testing the existance of more than one variable. The parameters are as follows: 1. Define Name This is the name of the variable. EXAMPLE #ifdef Var1 ... #endif #if Defined('Var1') = 'Y' | Defined('Var2') = 'Y' ... #endif ═══ 5.9.18. DieIfIoErrorOccurred() ═══ DieIfIoErrorOccurred() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to at any time prior to the closing of a file (stream) to determine if any input/output errors have occurred. The routine will display a message and abort PPWIZARD processing if an error has occurred. The parameters are as follows: 1. File Name This is the name of an unclosed file. ═══ 5.9.19. EnsureFileHasCorrectCase() ═══ EnsureFileHasCorrectCase() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine takes a filename as its only parameter and adjusts its filename as specified with the "/FileNames" command line switch. Note that while the intention of this routine is to adjust the case of filenames there is no reason why any rexx string can't be passed if you have the need. ═══ 5.9.20. Error() ═══ Error() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine is probably most useful in #import filter code and takes from 1 to 10 parameters. Each parameter contains the contents of a line to be displayed. The passed message line(s) will be displayed and PPWIZARD processing terminated. ═══ 5.9.21. ExpandXCodes() ═══ ExpandXCodes() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine can be called to expand codes. This routine is passed a single parameter. The codes are expanded and the result returned. ═══ 5.9.22. GenerateFileName() ═══ GenerateFileName() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function returns a filename which is translated in the same way as the "/Output" switch. It also ensures that any directory component of the generated filename exists. The parameters are as follows: 1. Name of a file This is the name of a file that is used as a basic for conversion using the second parameter. 2. Conversion Specification This tells PPWIZARD how to convert the first parameter. Example ;--- For the current input file work out a good name for a debug file --- #evaluate '' ^DebugFile = GenerateFileName('', 'out\*.DBG')^ ═══ 5.9.23. GetAmPmTime() ═══ GetAmPmTime() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes no parameters and returns the time including seconds with "am" or "pm" attached. ═══ 5.9.24. GetEnv() ═══ GetEnv() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function returns the value of an operating system environment variable. An empty string is returned if the variable is unknown. The parameters are as follows: 1. Variable Name This is the name of the environment variable. 2. Die if Missing? This optional variable is used to tell ppwizard to abort if the variable could not be found. To tell PPWIZARD to abort pass upper case 'Y'. Example ;--- Lets keep all WORK/HOME conditional logic here ------------------------- #define AtHome translate(GetEnv("PRJSRCDIR", 'Y')) = "E:\DB\PROJECTS\HOMEPAGE\HTML" #define AtWork translate(GetEnv("PRJSRCDIR", 'Y')) <> "E:\DB\PROJECTS\HOMEPAGE\HTML" ... ... ;--- External Links --------------------------------------------------------- #if <$AtHome> #define ExtLink {$VISIBLE=`{$URL}`} #elseif #define ExtLink {$VISIBLE=`{$URL}`}{$URL-} #endif ═══ 5.9.25. GetFileLineBeingProcessed() ═══ GetFileLineBeingProcessed() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes no parameters and returns the text of the current line being processed. The line is as read from a file and may or may not be the current line being processed (after macro expansion etc). The line being processed is available using the GetLineBeingProcessed() call. The returned line has been stripped of leading and trailing whitespace. This call would usually be called to remember details about a current situation which you may wish to report at some future stage. If using this call you may also wish to use GetInputFileNameAndLine(), see this section for an example of these calls in use. ═══ 5.9.26. GetFileTimeStamp() ═══ GetFileTimeStamp() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter (the name of the file we wish the date/time imformation of). If successful this routine returns a decimal number of the form "YYYYMMDDHHMMSS". The returned number can be compared with others to determine the newest file etc. You can substr() etc to transform the result into whatever format you desire. If the call fails (for example if the specified file does not exist) then a WARNING is generated and a return code of "-1" is returned. You can determine the day of the week for the file using the BaseDate routine. Example The following example shows how the date/time of a file can be retrieved and converted into whatever format you wish. Note that in the following macro I was careful not to redefine any variables and that a file not found is treated as a fatal error. #define GetFileDateTime \ #evaluate TmpDateTime ^GetFileTimeStamp("{$File}");^ \ #if <$TmpDateTime> = -1 \ #error ^The file "{$File}" was not found.^ \ #elseif \ #evaluate TmpDate ^substr('<$TmpDateTime>', 7, 2) || '/' || substr('<$TmpDateTime>', 5, 2) || '/' || left('<$TmpDateTime>', 4)^ \ #evaluate TmpHH ^substr('<$TmpDateTime>', 9, 2)^ \ #if <$TmpHH> < 12 \ #define TmpAmPm am \ #elseif \ #define TmpAmPm pm \ #endif \ #if <$TmpHH> > 12 \ #evaluate TmpHHAmPm ^<$TmpHH> - 12^ \ #elseif \ #evaluate TmpHHAmPm ^<$TmpHH>^ \ #endif \ #evaluate TmpTime ^"<$TmpHHAmPm><$colon>" || substr('<$TmpDateTime>', 11, 2) || '<$colon>' || substr('<$TmpDateTime>', 13, 2) || '<$TmpAmPm>'^ \ \ ;--- Output the information ("DD/MM/YYYY at HH<$colon>MM<$colon>SSam") --- \ <$TmpDate> at <$TmpTime> \ #undef TmpDate \ #undef TmpTime \ #undef TmpHH \ #undef TmpHHAmPm \ #undef TmpAmPm \ #endif \ #undef TmpDateTime ;--- Use my macro to get a timestamp -------------------------------------

The date/time stamp of "C:\AUTOEXEC.BAT" is "<$GetFileDateTime File="C:\AUTOEXEC.BAT">". ═══ 5.9.27. GetId() ═══ GetId() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is useful if you wish to ensure that all characters in a string are valid. This can be useful when you wish to use a value as a key of some sort. For the value that you pass, this routine will determine a unique key (or ID) of the format you requested. The routine has a memory and will always return the same ID for the same value. The function takes at least 3 parameters as follows: 1. A handle that was previously prepared with GetIdPrepare(). 2. The type of ID you'd like, valid types being:  2_ Non valid characters are converted to underscores. Leading and trailing underscores are removed. Duplicated underscores are also removed. The upper and lower case characters as well as zero to nine are always valid characters. You may specify additional valid characters in the optional 4th parameter to this function.  MAXCHARS The value is first converted in a similar manner to that used for "2_" mode. The leftmost 'x' chars are kept. The upper and lower case characters as well as zero to nine are always valid characters. You may specify additional valid characters in the optional 4th parameter to this function. The optional 5th parameter specifies the maximum number of characters in an ID with the default being 8. This type can be used to generate file names for a 8.3 based file system.  C2X Non valid characters are converted to 'x??', where '??' is the characters ASCII code in hexadecimal. The upper and lower case characters as well as zero to nine are always valid characters. You may specify additional valid characters in the optional 4th parameter to this function. 3. The value for which you want an ID generated. This is case sensitive, to make case insensitive simply convert your value to either upper or lower case before calling this routine. 4. Depending on the type of ID being generated there may be a 4th or other parameters. Example ;--- Example #1 --- #evaluate '' ^call GetIdPrepare 'PPW'^ #evaluate '' ^call SetId 'PPW', '#define', "HashDef"^ ;;Set preferred ID #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'define')^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', '#define')^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'define it')^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'define')^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'aaaaaaaaaaaaaaaa',, 10)^ ;;Max 10 chars #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'aaaaaaaaaaaaaaab',, 10)^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'aaaaaaaaaaaaaaac',, 10)^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'aaaaaaaaaaaaaaaa',, 10)^ ;--- Example #2 --- #evaluate '' ^call GetIdPrepare 'PPW'^ #evaluate '' ^say GetId('PPW', '2_', '#define')^ #evaluate '' ^say GetId('PPW', '2_', '#include', '#')^ ;;Allow Hash to be valid as well ═══ 5.9.28. GetIdPrepare() ═══ GetIdPrepare() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to prepare a handle for use in the GetId() routine. The function takes 2 parameters: 1. The handle to be used in GetId() and SetId(). 2. An optional parameter which if 'Y' means that you wish unique IDs generated by GetId() for what are probably non-unique values (or keys). When you specify unique IDs you are only allowed to use SetId() with a key of '' otherwise you are contradicting yourself! Normally when GetId() is called you pass it a unique key for which you wish a unique ID generated. If you ask for an ID for the same key at some later stage the original ID is returned. When 'Y' is used you intend to pass non-unique keys but YOU ensure or know that each time GetId() is called it is for a different entity even if the key looks identical! GetId() will generate a unique ID each time it is called and will not remember it. This mode can generate "prettier" IDs (at least until the key is duplicated) and without tricky code. The "FTPLIKE.IH" header file uses the "unique" mode. ═══ 5.9.29. GetImageHeightWidth() ═══ GetImageHeightWidth() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be used to automatically generate the HEIGHT and WIDTH parameters on a html "IMG" tag. The function takes 3 parameters (the 2nd and 3rd are optional), the parameters are: 1. The name of a file (.GIF or .JPG) 2. The width scaling factor (default = "100%"). 3. The height scaling factor (default = "?"). The scaling factor can be in these formats:  A number followed by a percentage sign scales the size by the amount specified. "50%" would halve the size while 200% would double it.  A number on its own (such as "100") fixes the size to the value supplied. It would be a common thing for the other sides size to be specified with "?" to have it scaled down in a proportional manner.  A "?" causes the side to be sized in the same proportion as the other side. Note that scaling both sizes of an image by "50%" gives you an image a 1/4 of the size. If an error occurs the routine aborts, otherwise a string similar to "WIDTH=10 HEIGHT=20" gets returned. Note that as the image file needs to be read to determine its size this routine will slow down the preprocessing of your files. You could get smart and generate an image header file of sizes (each one #defined) so that a separate slow step generates a header file that html source includes. Example ;--- 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}"> \ \ ;--- 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
═══ 5.9.30. GetInputFileNameAndLine() ═══ GetInputFileNameAndLine() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes no parameters and returns information about the current "location". It reports the current line number and file being processed. This information is already available in other forms ( & ) however this routine simplifies getting it into a nicely formatted output. If you are interested in this call you should probably also check out the GetFileLineBeingProcessed() and GetLineBeingProcessed() calls. Example This example has been extracted out of the standard PPWIZARD header file NESTCHK.H which can detect and report details of nesting errors such as forgetting a "" tag. #DefineRexx NestingInc_REXX ;--- Ensure ID is valid ------- if symbol('{$ID $$SQx2}_Level') <> 'VAR' then Error('The ID of "{$ID $$SQx2}" is unknown (you must use "NestingInit")!'); ;--- Increase nesting level --- call _valueS "{$ID}_Level", {$ID}_Level + 1; ;--- Record details about current location --- call _valueS "{$ID}_FilePosn.{$ID}_Level", GetInputFileNameAndLine(); call _valueS "{$ID}_CurrLine.{$ID}_Level", GetFileLineBeingProcessed(); #DefineRexx #define NestingInc \ #evaluate '' ^<$NestingInc_REXX ID='{$ID}'>^ The reported output (on nesting errors) looks something like: NESTING ERRORS ~~~~~~~~~~~~~~ Missing 2 end nesting tags on "HTML TABLE tag" * line 8 of "E:\DB\PROJECTS\OS2\ppwizard\1.in" <<$TABLE> COLS=1 blah blah> * line 9 of "E:\DB\PROJECTS\OS2\ppwizard\1.in" <<$TABLE> COLS=2 blah blah> ═══ 5.9.31. GetLineBeingProcessed() ═══ GetLineBeingProcessed() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes no parameters and returns the text of the current line being processed. The line returned is after macro expansion and may or may not be as read from the file. The line as read from the file is available using the GetFileLineBeingProcessed() call. The returned line has been stripped of leading and trailing whitespace. This call would usually be called to remember details about a current situation which you may wish to report at some future stage. If using this call you may also wish to use GetInputFileNameAndLine(), see this section for an example of these calls in use. ═══ 5.9.32. Info() ═══ Info() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine takes a single parameter which is displayed as if the #Info command was used. ═══ 5.9.33. InputComponentLevel() ═══ InputComponentLevel() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine takes a single parameter which is the include level that you are interested in. The full name of the input file at that level is returned. If you don't pass any value then the current level is assumed. If you pass an invalid value the empty string ("") is returned. This rexx routine does a similar job to the "" special variable (but for any level - not just the current one). Stupid Example Simple example in which one file works out who included it and at what line: ;--- Work out who included this file (and what line) --- #evaluate ParentFile ^InputComponentLevel(-1)^ #if '<$ParentFile>' = ''

There is no parent file! #elseif #evaluate ParentLine ^InputComponentLineLevel(-1)^

The parent file is: "<$ParentFile>" (line <$ParentLine>) #endif ═══ 5.9.34. InputComponentLineLevel() ═══ InputComponentLineLevel() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine takes a single parameter which is the include level that you are interested in. The line number being processed of the input file at that level is returned. If you don't pass any value then the current level is assumed. If you pass an invalid value the empty string ("") is returned. This rexx routine does a similar job to the "" special variable (but for any level - not just the current one). For an example of how it could be used have a look at the InputComponentLevel() routine. ═══ 5.9.35. IsDebugOn() ═══ IsDebugOn() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to simply determine whether debug is on or off or to determine the level of user debug currently active (see DebugLevel). This function would be useful if you wished to conditionally call Debug() or conditionally generate html comments in your output etc. The function takes either zero or one parameters as follows:  No parameters indicates that you simply want a Y/N response to whether or not debug is on (similar to "" variable).  If a parameter is supplied it should be a digit (one of 1, 2 or 3). If debug is off this routine will return 0 otherwise it will return the result of the supplied number anded to the value of the user bits (which of course could also result in 0). That is you can check on each bit seperately if you wish. If you simply wish to tell if any user debug state is on then pass 3, if you wish to check the state of one of your flags then pass it's value, a return code of 0 indicates that that level of debug is not on. ═══ 5.9.36. MacroGet() ═══ MacroGet() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter (the name of a macro) and returns its contents. The macro must already exist (created by #define or #evaluate). The value of the macro is returned, if this contains any macros to be replaced, macro parameters or commands to be executed they are not replaced or executed. If you need parameter substitution you could create unique strings and use ReplaceString() to perform the "substitution" yourself. Note that there is also a MacroSet() routine. ═══ 5.9.37. MacroSet() ═══ MacroSet() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to create a macro. Note that there is also a MacroGet() routine. The function takes 2 or 3 parameters as follows: 1. Name of variable. 2. The macros value. 3. Optional parameter, pass 'Y' if its OK to redefine the macro. ═══ 5.9.38. PadString() ═══ PadString() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function will generate a padded string, it can pad Left, Right or Center the string you supply. The function takes 3 parameters: 1. The string to be padded (never truncated if wanted length too short). 2. The length of the new string. 3. A single character (for Left, Right or Center). ═══ 5.9.39. ProcessNext() ═══ ProcessNext() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. PPWIZARD macros utilize a buffer to hold lines that they generate, these are read before the file is accessed. This function allows you to add data to be processed next. The function takes a single parameter which is the line or lines (for multiple lines they should separated with a newline character). This routine is handy where you may have captured some text, including references to macros etc and you wish to process the data where the data might otherwise be written directly to the output file. ═══ 5.9.40. QuoteIt() ═══ QuoteIt() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function will determine a quote character that is not contained within the string you pass. Processing will abort if it can not do so. The function takes 2 parameters: 1. The string that you wish to quote. 2. An option list of all possible quote characters. If not supplied it defaults to trying double then single quotes. This routine is handy when a macro is passed some information and needs to generate the data in a quoted format. Some languages such as HTML allow information to be quoted with either a single or a double quote. Stupid Example #evaluate '' ~RxQuote=QuoteIt('AS"DF')~ Should be double = #evaluate '' ~RxQuote=QuoteIt("AS'DF")~ Should be single = #evaluate '' ~RxContainsBothQuotes = 'AS"' || "'DF"~ #evaluate '' ~RxQuote=QuoteIt(RxContainsBothQuotes, '"' || "'^")~ Should be '^' = #evaluate '' ~RxQuote=QuoteIt(RxContainsBothQuotes)~ ;;Will die ═══ 5.9.41. ReplaceMacros() ═══ ReplaceMacros() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter (the string) and will return a new string where all Macros and standard symbols have been replaced. ═══ 5.9.42. ReplaceString() ═══ ReplaceString() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function will convert all occurances of a substring as you specify. The function takes 3 parameters as follows: 1. The string which is to be translated. 2. The FROM string. 3. The TO string. When this routine returns the rexx variable ReplaceCount will have been incremented by the number of replacements made. Note that its faster to use BulkChar2String() to modify a whole lot of characters to strings. Of course converting single characters to other single characters is better done with the rexx translate() routine. If you need to do case insensitive changes then use the ReplaceStringCI() routine. ═══ 5.9.43. ReplaceStringCI() ═══ ReplaceStringCI() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function will convert all occurances of a substring as you specify. The function takes 3 parameters as follows: 1. The string which is to be translated. 2. The FROM string. 3. The TO string. When this routine returns the rexx variable ReplaceCount will have been incremented by the number of replacements made. This routine is very similar to the ReplaceString() except that it is case insensitive and that the "TO" string may contain one or more "{*}" strings which will get replaced with the "FROM" string. ═══ 5.9.44. ReverseArray() ═══ ReverseArray() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to reverse the order of elements in an array. The "array" has numeric indexes with the ".0" element holding the number of elements. The function takes a single parameter which is the name of the array (without dot). The routine returns the number of items in the array. Silly Example ;--- Set up the array ----------------------- #evaluate '' \ ^ \ A.1 = "5345"; \ A.2 = "4123"; \ A.3 = "61743"; \ A.4 = "1678"; \ A.0 = 4; \ ^ ;--- Sort array & Reverse order & display --- #evaluate '' ^call SortArray "A"^ #evaluate '' ^call ReverseArray "A"^ #evaluate '' ^do I = 1 to A.0; say a.i; end;^ ═══ 5.9.45. RexGetTmpFileName() ═══ RexGetTmpFileName() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function returns the name of of currently non-existing file which can be used as a temporary file. If you want some control over the name of the file then you may pass a single parameter which is a filename with '?' in any positions where a "random" digit can be placed (example "IMP_????.TMP"). ═══ 5.9.46. SetEnv() ═══ SetEnv() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes two parameters as follows: 1. The name of the environment variable. 2. The new value ("" to delete it). The return value is the original value of the environment variable or "" if it did not exist. This command may be useful to pass information to any filters you may have set up (with /FilterInput or /FilterOutput). ═══ 5.9.47. SetId() ═══ SetId() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is useful if you wish to ensure that when GetId() is called a specific value for an ID is used. An example of where this might be useful is if you have external entry points into a set of generated html pages. You normally would not care what they are called as long as all the links work, however as soon as you wish externally generated html to link to specific pages you must do something to ensure that the links name does not change. The function takes 3 parameters as follows: 1. A handle that was previously prepared with GetIdPrepare(). 2. The value (KEY) for which you are specifying an ID This is case sensitive, to make case insensitive simply convert your value to either upper or lower case before calling this routine. There is one situation where you may wish to pass a empty key ('') and that is when you specified unique ID mode on GetIdPrepare(). You would do this to pass an ID that you never want returned by GetId(). 3. The ID you wish to give to the value (KEY). Note that this is not validated in any way. It is up to you to ensure its correct. Example #evaluate '' ^call GetIdPrepare 'PPW'^ #evaluate '' ^call SetId 'PPW', '#define', "HashDef"^ ;;Set preferred ID #evaluate '' ^say GetId('PPW', 'MAXCHARS', 'define')^ #evaluate '' ^say GetId('PPW', 'MAXCHARS', '#define')^ ═══ 5.9.48. SortArray() ═══ SortArray() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function is used to sort a rexx array. The "array" has numeric indexes with the ".0" element holding the number of elements. The array can hold numbers or strings. The sort is always ascending. You can use the ReverseArray() routine if required. The function takes 1 or more parameters as follows: 1. The name of the array (don't include the dot). 2. If you wish to sort only over specific columns then the starting column number (first column is 1). 3. If the optional starting column was specified then this specifies the ending column. If not specified then the rest of the string is used. 4. This is an optional parameter. Do you want a strict compare? If you do then pass 'Y'. A strict compare does not ignore leading and trailing whitespace, however it won't correctly sort numbers. The routine returns the number of items in the array. If you are sorting a very large array with a fixed known name then you might wish to have a look at the faster and more powerful PPWSORT.H header file. Silly Example ;--- Set up the array ------------------------ #evaluate '' \ ^ \ A.1 = "ASDFG"; \ A.2 = "4123"; \ A.3 = "61743"; \ A.4 = "1678"; \ A.0 = 4; \ ^ ;--- Sort array & display -------------------- #evaluate '' ^call SortArray "A"^ #evaluate '' ^do I = 1 to A.0; say '"'a.i'"'; end; say ''^ ;--- Sort array (start column 3) & display --- #evaluate '' ^call SortArray "A", 3^ #evaluate '' ^do I = 1 to A.0; say '"'a.i'"'; end; ═══ 5.9.49. Summary() ═══ Summary() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to add (or remove) details on the displayed summaries. The function takes parameters as follows: 1. The text for the left hand side (before ':'). 2. The text for the right hand side (after ':'). 3. Type of summary line as follows:  To see the details on this build's summary only then pass "" (or anything other than valid values shown below).  To see the details on this build and all future build's (other files) summaries then pass "A" or "ALL".  To see the details on the overall summary for all builds then pass "O" or "OVERALL".  To drop summary details whether user or system generated pass "D" or "DROP", in which case parameter 2 is ignored. The text in parameter 1 must EXACTLY match that in a summary line. Example ;--- Don't want to see operating system version --- #evaluate "" "call Summary 'Operating Syst',, 'D'" ;--- Add a summary line to this build ------------- #evaluate "" "call Summary 'Left', 'Right'" ═══ 5.9.50. ToLowerCase() ═══ ToLowerCase() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter and returns it in lower case. Note that there is no PPWIZARD "upper case" case routine as the standard rexx "translate()" routine with a single parameter does this nicely. ═══ 5.9.51. UrlDecode() ═══ UrlDecode() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to convert a string (encoded URL) back into its plain text format. The decoded string is returned. The parameters are as follows: 1. Input String This is the string which is to be decoded. 2. Mode Normally occurances of '+' are replaced with spaces. Pass "LEAVE+" to not handle the plus characters. ═══ 5.9.52. UrlEncode() ═══ UrlEncode() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function can be called to convert a string into a valid format for use in a URL. Characters such as '#' are converted to codes as they have special meanings when found within a URL. The new encoded string is returned. This routine should eliminate the need for having to see encoded URLs in your source code. The parameters are as follows: 1. Input String This is the string which is to be encoded. 2. Mode  EncodeAll All characters in the input string are encoded, so that it can be called as a poor man's encryption scheme. It can hide stuff (at least from casual browsing) in plain html code etc. A space in not encoded as a plus.  To% You need to supply a 3rd parameter which is a list of all characters that you would like to encode. A space in not encoded as a plus.  ? If you can tell me a scheme that is required then let me know and I can add it... 3. Mode Dependent Parameters There may be one or more extra parameters depending on the mode. Example #evaluate 'HiddenText' ^UrlEncode("Password", "EncodeAll")^ ═══ 5.9.53. Warning() ═══ Warning() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This routine is probably most useful in #import filter code and takes a two parameters. The first parameter is the message ID and the second is the message text, see the #warning command for more details. The passed warning message will be displayed. ═══ 5.9.54. WriteLineToTmpImportFile() ═══ WriteLineToTmpImportFile() This is a rexx function provided by PPWIZARD. This routine (like all PPWIZARD extensions) can be used with any operating system supported by PPWIZARD. This function takes a single parameter and has no return code (on failure PPWIZARD will terminate). It must only be called while #Import is being processed. You may pass one or more lines of data which will be written to the temporary file that pass one of an import generates. To indicate the end of a line the Linefeed character (decimal 10) should be used the actual characters written to the file are determined by the /CrLf state. For an example have a look at a complex import example. ═══ 5.9.55. _filespec() ═══ _filespec() This is a rexx function provided by PPWIZARD. This routine is named similar to an OS/2 specific call with a similar purpose, this PPWIZARD version works in all operating systems supported by PPWIZARD. This function takes two parameters as follows: 1. The part of the filename to extract. Valid are (note you are also allowed to passed only the 1st character of each command):  drive - Drive (example 'C:')  path - Path (example '\OS2\')  name - Shortname (example 'XCOPY.EXE')  location - Location (example 'C:\OS2\')  extn - Extension (example 'EXE')  withoutextn - No extension (example 'C:\OS2\XCOPY') 2. The name of the file. The return value is the extracted component you requested. It is important to note that a partial filename is not converted to its full name before extraction, the part is extracted from what you supply. It is also assumed that the filename is of a valid format. Example ;--- Capture some HTML information --- #evaluate ShortNameHtml ^_filespec('name', '')^ ═══ 5.9.56. _SysFileDelete() ═══ _SysFileDelete() This is a rexx function provided by PPWIZARD. This routine is named similar to an OS/2 specific call with a similar purpose, this PPWIZARD version works in all operating systems supported by PPWIZARD. This function takes a single parameter which is the filename to delete. This routine returns a non-zero return code on error. ═══ 5.9.57. _SysFileTree() ═══ _SysFileTree() This is a rexx function provided by PPWIZARD. This routine is named similar to an OS/2 specific call with a similar purpose, this PPWIZARD version works in all operating systems supported by PPWIZARD. This function takes two parameters as follows: 1. The name of a file or directory to look for (normally containing wildcard characters appropriate to the operating system being used). In linux specify a directory name with a terminating slash to capture all files or subdirectories in that directory. 2. The name of a rexx stem (array) to place the list of matching files (example "Files"). On return "Files.0" contains the number of files, "Files.1" contains the first filename etc. 3. List of options, supported are:  D - Directories only.  F - Files only (default).  S - Follow subdirectories. If successful a return code of 0 is returned. The contents of the "array" may not be valid if an error occurred so always either check the return code or preset the ".0" element to 0 before making the call. The full (absolute) name of files is always returned, however the names of directories may be absolute or relative depending on what you passed as the first parameter to this routine. ═══ 5.9.58. _SysSearchPath() ═══ _SysSearchPath() This is a rexx function provided by PPWIZARD. This routine is named similar to an OS/2 specific call with a similar purpose, this PPWIZARD version works in all operating systems supported by PPWIZARD. This function takes two parameters as follows: 1. The name of an environment variable which contains a sequence of directories to be searched (such as "PATH"). Unix unix directories should be separated by ':', for all other operating systems the ';' character should be used. 2. The file to be searched for. The return value is the full name of the file or '' if not found. ═══ 6. 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. Lets 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.cmd *.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. ═══ 7. Commands ═══ Commands The following commands are available to you when you use the PPWIZARD.CMD Preprocessor:  #AsIs  #AutoTag  #AutoTagClear  #AutoTagState  #debug  #define[+]  #DefineRexx[+]  #DependsOn  #ElseIf  #EndIf  #EOF  #error  #evaluate[+]  #if  #IfDef  #IfNDef  #import  #include  #Info  #MacroSpace  #OneLine  #OnExit  #option  #output  #require  #RexxVar  #UnDef  #warning The following commands allow you to perform PPWIZARD looping:  #{  #}  #break  #continue ═══ 7.1. #{ ═══ #{ This command is used to define the start of a loop which ends with the "#}" statement. You may use the #continue to restart at the top of the loop and #break will cause you to exit the loop. 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). 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 - Loop 12 Times ;--- Output 12 text lines --------------------------------------------------- #RexxVar Count = 1 ;;"#RexxVar" is fastest way to set or update a rexx variable #{ ;--- Output one line ----------------------------------------------------- From Loop #
;--- Only do 12 times ---------------------------------------------------- #RexxVar Count + 1 #if [ > 12] ;;Note the square brackets to improve performance (since simple test) #break ;;Now done 12 times #endif #}


;;Break sends us here Example 2 - 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 to read the above file and create the directories is: ;--- Code written for OS/2 so gain access to rexx extensions ---------------- #evaluate "" "call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'" #evaluate "" "call SysLoadFuncs" ;--- Define some directories ------------------------------------------------ #define site.root C:\sitetest #define site.out.dir <$site.root>\html ;;output root ;--- Make required base directories ----------------------------------------- #evaluate "" "MkDirRc=SysMkDir('<$site.root>')" #evaluate "" "MkDirRc=SysMkDir('<$site.out.dir>')" ;--- 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');^ ═══ 7.2. #} ═══ #} 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. ═══ 7.3. #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 "<". Its 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. ═══ 7.4. #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 its the second change etc. Note that its 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 ═══ 7.5. #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. ═══ 7.6. #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 - ═══ 7.7. #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. ═══ 7.8. #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. ═══ 7.9. #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' ═══ 7.10. #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 the command was "#define+" 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. 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. 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*> ═══ 7.11. #DefineRexx[+] ═══ #DefineRexx[+] This command provides a simple way to define multi line/statement rexx code without requiring line continuation characters. The rexx code would typically be executed at some later stage (if not immediately). Rather than execute the code you may wish to create a macro for later expansion when you use ppwizard as a rexx preprocessor. It then becomes a powerful tool of creating rexx code which can be used in multiple locations. 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. 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. 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). 6. 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 seperate 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["]]> 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 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. 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 in this circumstance is that the rexx code is not valid until the substitution has taken place, this confuses the packing logic. EXAMPLE #DefineRexx SomeRexxCode ;--- Comment to be removed (as are blank lines) --- 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. ═══ 7.12. #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. An input dependancy should be defined before the file is used. It does not matter when an output dependancy is defined. If /DependsOn was not specified then the command is ignored. Syntax [WhiteSpace]#DependsOn ["]DepType["] ["]StampWhat1["] ... The "DepType" parameter indicates whether the following files are input (source) files or output (target) files. 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 files date and time is used for the "stamp" however if the parameter starts with '*' then this has special meaning as follows:  *Files=[+]FileMask This allows a list of files matching a mask to be stamped in one hit. You should understand that this is not the same as stamping all the files matching the mask individually as the number of files matching the mask can change but a static list of files doesn't. 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.  *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". Example 1 - Two files specified #DependsOn INPUT "C:\CONFIG.SYS" "C:\STARTUP.CMD" Example 2 - 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=')'> ═══ 7.13. #elseif ═══ #elseif This command is used if you wish to have some lines included when the #if condition is false. ═══ 7.14. #endif ═══ #endif This command is used to terminate a previous #if command. There should be a matching #endif for every #if command. ═══ 7.15. #EOF ═══ #EOF This command marks where processing of the current file should be stopped. Anything after this command can be in any format as its 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. ═══ 7.16. #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. As well as supporting all standard rexx functions and any ".CMD" you care to write yourself, the following PPWIZARD preprocessor extensions can be called:  AddCommasToDecimalNumber()  AddInputFileToDependancyList()  AddOutputFileToDependancyList()  AddressCmd()  AsIs()  AsIsPrepare()  AutoTag()  BaseDate()  BreakAt()  BulkChar2String()  BulkChangePrepare()  CompareReplaceFixed()  DataGet()  DataSave()  Debug()  DebugIndent()  Defined()  DieIfIoErrorOccurred()  EnsureFileHasCorrectCase()  Error()  ExpandXCodes()  GenerateFileName()  GetAmPmTime()  GetEnv()  GetFileLineBeingProcessed()  GetFileTimeStamp()  GetId()  GetIdPrepare()  GetImageHeightWidth()  GetInputFileNameAndLine()  GetLineBeingProcessed()  Info()  InputComponentLevel()  InputComponentLineLevel()  IsDebugOn()  MacroGet()  MacroSet()  PadString()  ProcessNext()  QuoteIt()  ReplaceMacros()  ReplaceString()  ReplaceStringCI()  ReverseArray()  SetEnv()  SetId()  SortArray()  Summary()  ToLowerCase()  UrlDecode()  UrlEncode()  Warning()  WriteLineToTmpImportFile()  RexGetTmpFileName()  _filespec()  _SysFileDelete()  _SysFileTree()  _SysSearchPath() 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>
═══ 7.17. #Error ═══ #Error A #Error command is used to abort processing. You would probably have extracted information (maybe from an environment variable) and found that all is not right. This command allows you to halt processing and display an error 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. Example #if GetEnv('FRED') <> 1 & GetEnv('FRED') <> 2 #Error "Invalid value for variable 'FRED'" #endif ═══ 7.18. #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) Its 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. ═══ 7.19. #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 its recommended that you use #ifdef and #ifndef commands where possible. Syntax [WhiteSpace]#ifdef VariableName The "VariableName" specifies a variable that should exist for the test to evaluate to true. Example #define Fred FredsValue #ifdef Fred ... #endif ═══ 7.20. #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 its 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 ═══ 7.21. #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 as expanded. If debug is not on then after pass two completes the temporary file is deleted. Turn debug on an examine the temporary file if things are not going to plan! 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 does not support SQL directly but it doesn't need to as it can interface to any database if a rexx interface is available.  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. ═══ 7.21.1. #import - SQL DATABASES ═══ #import - SQL DATABASES This example shows you how to access data using the "mSQL" (free) database program. The database we will process is called "supersite" and the table we will access is "link". This example makes use of Mark Hessing's RexxSQL library to access the database program. It's free and is available for multiple operating systems and can access many different database programs. Its available from "http://www.lightlink.com/hessling/". You may want to have a look at the #evaluate routines AsIs() and AutoTag(). mSQL EXAMPLE ;--- Very simplistic start of HTML ------------------------------------------

Example - Create Links List from SQL Query

;--- Initialization --------------------------------------------------------- #define QueryCategory 3 ;;This query is for this category #define LinkTemplate

{$title}: {$description} ;;HTML for each record (note that it would be more efficient (but less "clean") to just pick up rexx variable names here ;--- Enable PPWIZARD to make use of external SQL library -------------------- #evaluate '' "call RXFuncAdd 'SQLLoadFuncs', 'rexxsql', 'SQLLoadFuncs'" #evaluate '' "call SQLLoadFuncs;" ;--- Connect to the data base ("supersite" on local machine) ---------------- #evaluate 'ConnectRc' "SQLConnect('PPW',,, 'supersite', 'localhost')" ;--- Perform a database query (on the table "link") ------------------------- #evaluate+ 'QueryRc' ^SQLCommand('RxLink', 'SELECT * FROM link WHERE category = <$QueryCategory>')^ #info 'QueryRc = <$QueryRc>' #info 'Number of records is ' ;--- Generate the html (for simple list) ------------------------------------

;;End of list ;--- Disconnect the data base ----------------------------------------------- #evaluate 'DisConnectRc' "SQLDisconnect('PPW')" ;--- Very simple end of HTML ------------------------------------------------


End of simple SQL IMPORT Example
═══ 7.21.2. #import - Delimited Records ═══ #import - Delimited Records These type of #Imports have 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. Field Information Parameters On these types of imports "FieldInfo" followings the "DefineName" parameter. 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. 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. - 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. - 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_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 its 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" ═══ 7.21.3. #import - Fixed Field Records ═══ #import - Fixed Field Records These type of #Imports have 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" followings the "DefineName" parameter. 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 its 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. 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. - 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. - 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_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" ═══ 7.21.4. #import - Multi Line Records ═══ #import - Multi Line Records This type of #Imports have 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" followings the "DefineName" parameter. 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 its 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. 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. - 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. - 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_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_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 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}" ═══ 7.21.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. 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 "" ═══ 7.21.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. 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> ═══ 7.22. #include ═══ #include A #include can be used to include another 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. 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. 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 example. 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 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. Note that if an input file can't be located (relative to the current directory), the following environment variables paths will also be searched (in order): 1. PPWIZARD_INCLUDE 2. INCLUDE After searching the above locations the directory PPWIZARD is located in is also examined. 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 ═══ 7.23. #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." ═══ 7.24. #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 ═══ 7.25. #OneLine ═══ #OneLine 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! 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. Syntax [WhiteSpace]#OneLine [["]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 "#OneLineEnd" (note that the current prefix is used). Lines are combined until this text is located (in this exact case). EXAMPLE #OneLine #define SomeWords The rain in sp -\ ain falls mainly on the plain #OneLineEnd ;;Marks end of block! #OneLine '' '@@' T h e rain @@ ;;Marks end of block! ═══ 7.26. #OneLineEnd ═══ #OneLineEnd There is no such command although it may at first glance appear so. The text "#OneLineEnd" is simply the default end of #OneLine block marker if no alternative was specified. ═══ 7.27. #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. 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. This command may be used any number of times, the "on exit" processing occurs in the order that the commands were executed. Note that the processing does not occur if a fatal error was detected. Syntax [WhiteSpace]#OnExit TheText The text can be anything (macro reference etc). The parameter(s) are not expanded until exit processing occurs. The following is used in one of my header files: ;--- Register checking macro --- #OnExit <$NestingCheck> ═══ 7.28. #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  Replace  ReplacementTags  WhiteSpace 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 ═══ 7.28.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 ═══ 7.28.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 ═══ 7.28.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 its 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) ═══ 7.28.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). 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 ═══ 7.28.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. Its 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.  CONDITIONAL #if, #endif output 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.  AFTERREPLACE All display of lines after some sort of replacement such as that by #AsIs commands or your macros.  OPTIONS Any output related to #option command.  OPSYS Debug commands executed by operating system.  DEFINING Output related to defining variables/macros.  MACROVALORDEF PPWIZARD allows some things to be defined via a macro, there is usually a default value. This debugs these situations.  SPELLING Show all spelling related output?  ASIS Debug the #AsIs command.  AUTOTAG Debug the #AutoTag command.  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.  EVALUATE This debugs PPWIZARD functions that can be used in #evaluate or #if commands etc.  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.  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 its still very useful. 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~ ═══ 7.28.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 its 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; ═══ 7.28.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 ═══ 7.28.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" ═══ 7.28.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" ═══ 7.28.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 its 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 ═══ 7.28.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 ═══ 7.28.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 -------------------- ═══ 7.28.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>-+ ^ ═══ 7.28.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 ═══ 7.28.15. 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 \ ═══ 7.28.16. 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 ═══ 7.28.17. 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}~" ═══ 7.29. #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] [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. 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: #output "NUL" ASIS APPEND ;;Drop output! This line gets dropped #output ;;Stop dropping output! ═══ 7.30. #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["] The "MinVersion" specifies the minumum version number of PPWIZARD. The preprocessing will abort if the preprocessor is too old. Example #require 98.216 ;;Want PPWIZARD version 98.216 or greater ═══ 7.31. #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 is the only supported way to define "" 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 its 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 its 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 its quoted): #RexxVar 'MyVar' = /ABC/ The following is sets the rexx variable "MyVar" to the contents of the variable "ABC" (as its 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 ═══ 7.32. #undef ═══ #undef A #undef command allows you to remove a definition so that it can be redefined without producing the warning message it normally will generate. Syntax [WhiteSpace]#define Variable The "Variable" indicates which variable is to be removed. Example #define Fred Its value #undef Fred; #define Fred Its new value ═══ 7.33. #Warning ═══ #Warning A #Warning command is used to inform the user of an unusual situation. You would probably have extracted information (maybe from an environment variable) and found that all is not right. This command allows you to warn the user but continue processing (you will get a return code of 1). The #Error command is similar but halts processing. Syntax [WhiteSpace]#Warning [']WarningId['] [']WarningMessage['] The "WarningId" parameter specifies a warning ID which can be used to help identify message (for example if you wished to use the /WarningsIgnore switch). You can supply an empty ID in case no ID is used. An ID can be as short or long as you wish. The "WarningMessage" parameter specifies the text of the warning to be displayed. Example #if GetEnv('FRED') <> 1 & GetEnv('FRED') <> 2 #Warning ^IV00^ "Invalid value for variable 'FRED', processing will continue" #endif ═══ 8. Standard Definitions ═══ Standard Definitions There are a number of "standard" definitions which have been predefined and can be placed almost anywhere in your source code. The variables can be in any case, they are:                                      Note that you can define your own variations of "standard" variables with the "#evaluate" command, for example to create an alternative way to display the Compile Time. EXAMPLES OF CREATING VARIABLES ;--- Capture some HTML information ------------------------------------------ #evaluate ShortNameHtml "_filespec('name', '')" #evaluate ShortNameHtmlLowerCase "translate('<$ShortNameHtml>', 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" ;--- Capture date/time information (<$DateTime> --> Friday March 27 1998 at 7<$colon>46pm --- #evaluate DateTime @date('WeekDay') || ' ' || date('Month') || ' ' || substr(date('Sorted'), 7, 2) || ' ' || left(date('Sorted'), 4) || ' at ' || time('Civil')@ ;--- Create YY.DDD Version # (example "98.107") -------------------------------------- #evaluate YYDDD ~substr(date('Sorted'),3,2) || '.' || date('Days')~ ;--- 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=')'> ;--- Outputs the date (Ausi format... YES!) (takes parameter "File") -------- #define DateOfFile \ #evaluate+ LocalFileName ^ReplaceString("../{$File}", "/", "\")^ \ #DependsOn INPUT "<$LocalFileName>" \ #evaluate+ TmpFileTime ^stream("<$LocalFileName>", "c", "query datetime")^ \ #if "<$TmpFileTime>" = "" \ #error $Failed getting date/time of "<$LocalFileName>"$ \ #endif \ #evaluate+ TmpFileDate ~substr('<$TmpFileTime>', 4, 2) || '/' || left('<$TmpFileTime>', 2) || '/' || substr('<$TmpFileTime>', 7,2)~ \ <$TmpFileDate> #define DateOfFileInSmallFont {$Before=""}<$DateOfFile File=*{$File}*>{$After=""} ═══ 8.1. ═══ It is possible to access rexx variables without first obtaining a copy of their value with the "#evaluate command. Any symbol that starts with is a command to get the value of the rexx variable between. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example The following is an example which creates

,

HTML tagging etc: #RexxVar HeadingLevel = 1 ;;Create a rexx variable (set to 1) #RexxVar HeadingLevel + 1 ;;Increase value by 1 >A heading> ;;Use it ═══ 8.2. ═══ A "variable" of this type allows you to evaluate a rexx expression, without using a separate #evaluate command. Each time you use it a relatively slow rexx "interpret" command is required, so for performance reasons it is recommended that you:  Use "" to obtain the contents of a single rexx variable.  Use a single "#evaluate" command and store result for reuse rather than using the same rexx "variable" expression multiple times. The rexx expression has the limitation that it must not contain the ">" character! This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example ;--- 5 '*' chars ---- ;--- Next line is invalid (compile will fail) --- ',3)> ═══ 8.3. ═══ This variable expands to the following 2 lines: 1. Content-type: text/html 2. Blank line This is required at the start of all CGI output. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.4. ═══ This variable contains the date and time the compile started. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.5. ═══ This variable will tell you whether debug is currently on or off by returning 'Y' (it's on) or 'N'. You could use this to add comments to generated output when debug is on etc. You could also use the IsDebugOn() to obtain similar information. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.6. ═══ This variable will indicate the character used to separate components of a path. For most operating systems this will be '\' however UNIX uses '/' instead. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.7. ═══ This variable will be replaced by a '$' character. You may need to use it in some situations, for example in some cases where you wish to place '<$'. This symbol actually expands to a code and not the '$' character directly. In some cases this may not be what you wish and you should either define your own alternative or use some other method (#define may be suitable in a lot of cases) depending on your need. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.8. ═══ This variable will be replaced by a '#' character. This symbol actually expands to a code and not the '#' character directly. In some cases this may not be what you wish and you should either define your own alternative or use some other method (#define may be suitable in a lot of cases) depending on your need. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.9. ═══ This variable will be replaced by a current hash prefix character(s). This is whatever was set with the 'HashPrefix' option. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.10. ═══ This variable contains the level of file inclusion starting at 1. For each #include it goes up by one and goes back down by 1 when processing of that file completes. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.11. ═══ This variable contains the full filename of the input file currently being processed. If you need to access the name of an input file other than the current one, then you will need to use the InputComponentLevel() routine. If you need the name of the base source file (determined from the InputMask specified on the command line) and you are obtaining the information within your standard header files you will need to use "" instead. If you require the path or short name component then use the "#evaluate" command to subdivide the full name. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.12. ═══ This variable contains the current line number of the input file currently being processed. If you need to access the line number of other included files, then you will need to use the InputComponentLineLevel() routine. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.13. ═══ This variable contains the full filename of the base input file that was specified on the command line. This definition is useful to extract this information in your standard header files as "" could return the name of the header file! If you require the path or short name component then use the "#evaluate" command to subdivide the full name. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.14. ═══ This variable will return the newest source files date/time (so far) allowing you to date/timestamp your output with this information and not the date/time of the compile. Note that the "compiler" (PPWIZARD) is considered to be a source file as it also determines the format of the output. If the variable is used after the last #include to be processed then the value returned must be the date/time of the latest file (so unless you are added the timestamp information near the end of your output you may not be able to make use of this variable). The information is returned in the same format as that returned by the "GetFileTimeStamp()" routine (except that -1 is not possible). Also have a look at it's example as the macro it shows could be used with very minor modification. It is possible to work out the day of the week if you use the basedate routine. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.15. ═══ This variable forces following text onto the next line. It can be useful if you need to pass the generated html through other tools which can't handle long lines. In macros (created with "#define") this is the only way to ensure that multiple lines are generated. Note that this variable is the only way to ensure that the line is terminated correctly as the "/CrLf" switch (and others) may vary the appropriate codes that need to be generated. This symbol actually expands to a code and not the 'newline' character directly. In some cases this may not be what you wish and you should either define your own alternative or use some other method (#define may be suitable in a lot of cases) depending on your need. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.16. ═══ This variable indicates the operating system you are running on and is one of the following values:  OS/2  DOS  WINNT  WIN98  WIN95  UNIX If you need to know which version of a platform you will need to do more work yourself. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.17. ═══ This variable contains the full filename of the current output file. If you require the path or short name component then use the "#evaluate" command to subdivide the full name. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.18. ═══ This variable contains the output nesting level. When its '1', the output goes to the default output file, each #Output with filename adds one while a #output without file subtracts one. This variable would be handy in complex macro sets where #output commands are automatically generated. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example This line is at Output Level 1 #output '2nd' This line is at Output Level 2 #output 'c<$colon>\path\3nd.ext' AsIs This line is at Output Level 3 #output This line is at Output Level 2 #output This line is at Output Level 1 ═══ 8.19. ═══ This variable contains the line number of the next line to be generated ("this line") into the current output file. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.20. ═══ This variable contains the name of the developer of the PPWIZARD program. Use if you wish to make mention of PPWIZARD on your homepages. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.21. ═══ This variable contains the email address of the developer of the PPWIZARD program. Use if you wish to make mention of PPWIZARD on your homepages. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.22. ═══ This variable contains the internet address of the computer home page of the developer of the PPWIZARD program. Use if you wish to make mention of PPWIZARD on your homepages. Note that I recommend that if you point to other pages of mine that you either use a #evaluate on this variable to obtain the base path or validate that it contains what you expect (and fail with #error if it doesn't). This way if I change my homepage you will be informed via a new version of PPWIZARD. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.23. ═══ This variable contains the default HTML meta tags for this program. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.24. ═══ This variable contains the current processing mode, that is one of the following: 1. HTML 2. REXX 3. OTHER The mode can be set or specified in these situations: 1. /REXX 2. /HTML 3. /OTHER 4. #output This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.25. ═══ This variable contains the address of this programs HTML home page. Use if you wish to make mention of PPWIZARD on your homepages. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.26. ═══ This variable expands to one or more commands that ensure that following lines are protected from change by PPWIZARD. As examples, this prevents leading whitespace removal and text such as "#define" as being treated as commands. This is similar to the "#AsIs" command except that no "as is" tagging is performed and that PPWIZARD commands are not precessed. Note that this does not do any extra tagging such as that required to ensure that the text appears the same in a browser or ipf viewer etc. This must be taken care of by you ("#AutoTag"). You must use "" at the end of the lines you wish to protect. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.27. ═══ Please see "" for details. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.28. ═══ By the time PPWIZARD macro replacement has taken place its already decided that the line does not contain a PPWIZARD command. If you wish to dynamically generate PPWIZARD commands you need to use this variable at the start of every command (you could have more than one). Another possible reason for using this define is that PPWIZARD expands definitions in a single pass from left to right. This means that you could not build up a reference to a variable from components unless you include this define. PPWIZARD will stop replacement of macros etc as soon as it has expanded the first define of this type on the line so its position on a line can greatly affect the way expansion occurs. The use of this variable could cause other unwanted affects, it is up to you to test to ensure you are obtaining the results you require. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example In this example the intention is to create the macro variable "X": ;--- "Command" contains the command we want executed --- #define Command #define X XXXXXXXXXXXXXXXXXXXXX Attempt 1 - Fails ~~~~~~~~~~~~~~~~~ <$Command> Attempt 2 - Works ~~~~~~~~~~~~~~~~~ <$Command> Test Definition ~~~~~~~~~~~~~~~ Number of x's ==> <$X> ═══ 8.29. ═══ This symbol is used in conjunction with the "" symbol to simplify the "skipping" of subroutines within a rexx header file. A header file will frequently include some initialization code followed by some routines. The recommended place to include header files is at the start of your mainline code module. To be able to hold common procedures in the header file you must skip over them after you have performed any required initialization. You could simply use a "signal EndRexxHeader" before the procedures and "EndRexxHeader:" after, however then you need to create a new label every time and it becomes difficult to include a header file more than once. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example - EXAMPLE.XH /*--- Initialization for "EXAMPLE.XH" ---*/ call InitStuff; InitStuff: ... return; MoreCode: ... return; /*--- End of rexx header ---*/ ═══ 8.30. ═══ This symbol is used in conjunction with the "" symbol to simplify the "skipping" of subroutines within a rexx header file. Every use of "" must be followed by the use of the "" symbol. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example See . ═══ 8.31. ═══ This variable will be replaced by a single semicolon (;) character. It could be useful if you have the odd line that must begin with a semicolon. The semicolon is the default character to begin a line comment. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.32. ═══ This variable will be replaced by a single space, it is most useful for ensuring that you have required spaces on lines that were continued using the '\' character. This symbol actually expands to a code and not the ' ' character directly. In some cases this may not be what you wish and you should either define your own alternative or use some other method (#define may be suitable in a lot of cases) depending on your need. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.33. ═══ If the "/Template" switch was not specified then this variable will return an empty value, otherwise the name of the data file is returned (the template typically processes this file). By using this variable a header file could determine whether or not template processing is occurring. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.34. ═══ This variable contains the total line number of lines generated into all output files. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.35. ═══ This variable will be replaced by a Unique number every time it is used. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). ═══ 8.36. ═══ This variable will be replaced by the version number of the program. The version number is in the form "YY.DDD", examples are "98.001" (first day of 1998) and "00.123" (123rd day of 2000). This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Example The following code shows how you could ensure that a general purpose header file can only be used if the preprocessors version number is greater than a particular value. You would do this if the header file requires a particular feature which only became available in a specific release. /*--- Get PPWIZARD version # as YYYY.DDD ------------------------------------*/ #if < 98.000 #evaluate PPWizardVersion "2000.00 + "; #elseif #evaluate PPWizardVersion "1900.00 + "; #endif /*--- Validate PPWIZARD VERSION (Y2K safe) ----------------------------------*/ #define DEFINEIT_MIN_PPWIZARD_VERSION 1998.188 ;;Rely on changes made in specific PPWIZARD release #if <$PPWizardVersion> < <$DEFINEIT_MIN_PPWIZARD_VERSION> #error 'PPWIZARD.CMD version of at least <$DEFINEIT_MIN_PPWIZARD_VERSION> is required, you have <$PPWizardVersion>' #endif ═══ 8.37. ═══ Any variable which starts with 'x' has a special characteristic in that they are not replaced until just before a line is written to the output file. The only invalid character in the name of the variable is '>'. The replacements are made in a single pass from left to right. The replacement contents may not itself contain codes you wish to be interpreted in any way as the text will be output as specified. You have some control over when the replacement occurs, see the ExpandX option. The name of the symbol represents a variable whose contents was previously defined with the '=x=' operator of the #RexxVar command. For complex values you may need to first use #evaluate to calculate the value. Variables of this type are useful if you wish to use characters that can't be entered by the editing tool you are using. They also provide an emergency way out which might get you past instances where the character might otherwise be interpreted in a manner other than you wish. For example if you must have the string "" in your output (and not have it replaced by the version number)! Another example is that "" is the only way to get a tab into the generated output. This is a Standard Definition which always exists (you don't need to #define it). Note that you can create your own variations or completely new ones (see the examples). Codes to The 256 rexx variables "x00" to "xFF" have been preset to represent their ASCII character codes. This means that "" would get replaced with a tab character and "" would get replaced with "A". You could if you wished change the appropriate rexx variables to change the replacement value. For example you could decide the code for "<" gets replaced by "<" instead. Note that it would generally be better to "name" your ASCII codes as they would then be easier to understand, for example "xTAB" is a lot easier to understand than "x09"! It is highly recommended that you do not use "" codes to generated newlines, you should use "". Example - Using Predefined ASCII Codes #define Tab Col1<$Tab>Col2<$Tab>Col3 Example - Creating Your Own Codes #evaluate 'Tab' "d2c(9)" #RexxVar "TAB" =x= "<$Tab>" ;;TAB Char #RexxVar "LA" =x= "<" ;;'<' Char #RexxVar "RA" =x= ">" ;;'>' Char Col1Col2Col3 = Less than = Greater than ═══ 9. PPWIZARD Extensions ═══ PPWIZARD Extensions You may not wish to use some of these headers but it would pay you to look at them purely from the point of view of examples. ═══ 9.1. FTPLIKE.IH - Make "FTP" Like Listings ═══ FTPLIKE.IH - Make "FTP" Like Listings This header file will scan the specified directory (and optionally its subdirectories) and by default produce a FTP like set of html pages. It is very simple for you to modify any part of the look and feel, so for example it would be simple to add your own headers, footers, backgrounds and display all information in whatever format or font you wish. This header could also be used to automatically process photo directories producing thumbnails (with extra software) etc automatically. Example - Creating Directory Listing The following code is all that is required to generate a complete HTML page of all files in a single directory. Note that file descriptions are read out of ".DIZ" files if available (the DIZ files themselves are not displayed). ;--- Complete code to generate a HTML page for the directory "C:\TMP" --- #define FTPLIKE_DIRECTORY C:\TMP #define FTPLIKE_DIRECTORY_WEB file:///C|TMP ;;Note: for web "downloads/tmp" might normally be more appropriate #define FTPLIKE_FOLLOW_SUBDIRECTORIES #define FTPLIKE_USE_LONG_FILENAMES ;;When generating web pages for subdirectories (default is 8.3) #define FTPLIKE_HTML_EXTN html ;;When generating web pages for subdirectories (".htm" is default) #include "FTPLIKE.IH" Example - WPS URL Objects to HTML I keep all my WPS URL objects off a main URL folder, I then create HTML pages from this so I can effectively access my URL objects from anywhere via the internet (pages at http://www.labyrinth.net.au/~dbareis/bookmark.htm). This is the code I use: #define Title "Dennis' Personal Bookmarks" #define AddToDescription Dennis' Personal Bookmarks, straight from OS/2 WPS URL Objects #include "computer.ih" ;--- Initialization --------------------------------------------------------- #if ['' <> 'OS/2'] #error "Sorry but you will need to modify this file to work on operating systems other than OS/2!" #endif #evaluate "" "call RxFuncAdd 'SysGetEA', 'RexxUtil', 'SysGetEA'" ;--- Title ------------------------------------------------------------------ <$BackgroundMainWindows> <$PageTitle TITLE="Dennis' Personal Bookmarks"> ;--- Routine used to format "thin" URL -------------------------------------- #define ThinUrl \ #evaluate @@ @ThinUrl = BreakAt(14, '{$HTTPURL}')@ -\ ;--- Save values of this pages info (they get modified below!) -------------- #ifndef VERSION_PUSHPOPM_H #include "PushPopM.H" #endif <$MacroPush Macro='ShortNameHtml'> <$MacroPush Macro='ShortNameHtmlLowerCase'> ;--- Override images my footer macro normally uses for these pages ---------- #define+ LinkImgFooter -\ <$ImgMadeWithPpwizardAndreaResmini ALT="Made with PPWIZARD using FTPLIKE.IH"> -\ ;--- Override "normal" FTPLIKE options (no need to change header!!!!) ------- #DefineRexx REXX_GETURL ;--- First line of WPS URL file contains the URL ---------------- CloseRc = stream(FtpFile, 'c', 'close'); eUrl = linein(FtpFile); CloseRc = stream(FtpFile, 'c', 'close'); #DefineRexx #DefineRexx REXX_GETCOMMENT ;--- Comment is stored in OS/2 Extended Attributes -------------- if SysGetEA(FtpFile, ".COMMENTS", "eComment") <> 0 then eComment = ''; else eComment = substr(eComment, 11); ;;Drop EA Type info eComment = ReplaceString(eComment, '0D0A'x, '
'); #DefineRexx #DefineRexx REXX_REALNAME ;--- Long name is stored in OS/2 Extended Attributes ------------ if SysGetEA(FtpFile, ".LONGNAME", "eShort") <> 0 then eShort = ''; else eShort = substr(eShort, 5); ;;Drop EA Type info if eShort = '' then ;;Play safe! eShort = FtpOutput; ;;Use what we have! else eShort = ReplaceString(eShort, '0D0A'x, '
'); #DefineRexx #define FTPLIKE_DIR_HANDLER \ #evaluate+ '' ^FtpFile=FtpDir;<$REXX_REALNAME>;<$REXX_GETCOMMENT>^ -\ -\ -\ ;--- Link to HTML page we will create --- -\ <$FTPLIKE_LINK2DIR Url="<$FtpDirId>.<$FTPLIKE_HTML_EXTN>"> -\ ;;Just output short name -\ -\ -\ -\ -\ -\ -\ #if FtpSubdirTotalDirCnt <> 0 -\ -\ #endif -\ -\
url(s) folder(s)
-\ #if [eComment <> ''] -\
;;Comment from EAs -\ #endif -\ -\ #define FTPLIKE_FILE_HANDLER \ #evaluate+ "" "FtpOutput = _filespec('name', FtpFile)" -\ #evaluate+ '' ^<$REXX_GETURL>;<$REXX_REALNAME>^ -\ ;;Start New File row %\ ;;Start filename cell %\ -\ ;;Just output short name -\ %\ ;;End cell \ ;;Start filename cell %\ <$ThinUrl HTTPURL=""> -\ ;;End cell #define FTPLIKE_FILE_DETAILS_HANDLER \ #evaluate '' ^<$FTPLIKE_FILE_ATTRIBUTE_HANDLER_REXX>^ -\ ;;Start file details cell %\ \ :: \ #evaluate "" ^<$REXX_GETCOMMENT>^ -\ #if [eComment <> ''] -\
;;Comment from EAs -\ #endif -\ ;;End cell %\ ;;End this File row #define FTPLIKE_END_PAGE_ABOVE_FOOTER \ <$ImgBarbedWire> -\
-\

Creating These Book Mark Pages

-\
-\ -\

This page was automatically created from \ OS/2 WPS URL objects created with Netscape 4.04 \ onwards. \ The free tool used was \ PPWIZARD using \ -\ this source code \ . -\ -\

All URLs are checked periodically using the \ URL checking tool that comes with PPWIZARD. #define FTPLIKE_NO_HEADER_FOOTER_ON_1ST_PAGE #define FTPLIKE_FOLLOW_SUBDIRECTORIES #define FTPLIKE_USE_LONG_FILENAMES #define FTPLIKE_BODY_TAG <$BackgroundMainWindows> #if <$AtHome> #define FTPLIKE_DIRECTORY E:\DB\URLS ;;HOME: Location of Base WPS URL folder #else #define FTPLIKE_DIRECTORY ..\HOME_URL ;;WORK: Copied here from home #endif #define FTPLIKE_DIRECTORY_WEB #define FTPLIKE_NEWHTML_PREFIX bookmark_ #define FTPLIKE_HEADER <$PageTitle TITLE="{$Title}"> #define FTPLIKE_FOOTER \ #evaluate+ ShortNameHtml "_filespec('name', '')" -\ #evaluate+ ShortNameHtmlLowerCase "translate('<$ShortNameHtml>', 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" -\ <$EndHtmlWithStandardFooter> ;--- Include FTPLIKE support (creates all HTML pages based on options above) --- #include "FTPLIKE.IH" ;--- Restore this pages information and output footer and end of HTML ------- <$MacroPop Macro='ShortNameHtmlLowerCase'> <$MacroPop Macro='ShortNameHtml'> <$EndHtmlWithStandardFooter> FTPLIKE.IH This shows the contents of the header file (supplied with PPWIZARD) that provides the generic "FTP like" support: ;---------------------------------------------------------------------------- ; MODULE NAME: FTPLIKE.IH ; ; $Author: Dennis_Bareis $ ; $Revision: 1.8 $ ; $Date: 25 Nov 1999 17:57:06 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/FTPLIKE.IHV $ ; ; DESCRIPTION: This allows you to create FTP like pages without ; having to do a lot of work. Simply add the file ; to a directory will get it onto the correct HTML ; page. ; ; It would be wise to generate pages into their own ; directory on the off chance that this header file ; picks a name for a directories file which matches ; one of yours! ; ; Note that most of the code below is tricky only ; because I made it generic (ie very configurable), ; a specific implementation would be much smaller ; and much much easier to write as well! ; ; The whole look and feel of the generated data may ; be modified. ; ; It would be simple to have your normal look and feel ; items such as headers, footers backgrounds etc ; integrated into the generated output. ; ; Description file support (.diz) is available for both ; files and directories. The directory DIZ file should ; reside in the directory its describing. Note that the ; file can (and probably should) contain normal HTML ; formatting tags - by default anyway. If you have a ; file called "stuff.zip" this header will look for ; "stuff.zip.diz" and "stuff.diz". ; ; You should not modify the value of any definition ; that begins with an "_", you can modify virtually ; anything else. ; ; Note that dependancy checking does not make sense ; in this type of situation as files can appear simply ; by matching the wildcard. For this reason I do not ; bother with using the "#dependsOn INPUT" command for ; each file I process. ; ; ; NOT COMPLETE ; ~~~~~~~~~~~~ ; I don't really like the way file date, time and size ; are displayed, if you have any better ideas please ; let me know. ; ; ; SUPPORTED OPERATING SYSTEMS ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; It is intended that all operating systems that PPWIZARD ; supports can also use this header, if you find that ; it does not work then please send me the output when ; you have used the "/debug" command line switch. Please ; also include a directory listing of the directory(s) you ; are processing. ; ; ; EXAMPLE - LINUX ; ~~~~~~~~~~~~~~~ ; #define FTPLIKE_FOLLOW_SUBDIRECTORIES ; #define FTPLIKE_USE_LONG_FILENAMES ; #define FTPLIKE_DIRECTORY /home/dennis/ ; #define FTPLIKE_DIRECTORY_WEB http://ftp ; #include "ftplike.ih" ; ; ; EXAMPLE - OS/2, WINDOWS ; ~~~~~~~~~~~~~~~~~~~~~~~ ; #define FTPLIKE_FOLLOW_SUBDIRECTORIES ; #define FTPLIKE_USE_LONG_FILENAMES ;;Remove this definition for 8.3 names ; #define FTPLIKE_DIRECTORY C:\TMP\ASM_MAC ; #define FTPLIKE_DIRECTORY_WEB file:///C|TMP/ASM_MAC ;;Local testing ; #include "FTPLIKE.IH" ; ; ; HELP WANTED ; ~~~~~~~~~~~ ; I use "find" under linux, is there a expression that ; I can pass to "-name" to display all files/directories? ; ;---------------------------------------------------------------------------- ;--- First time through? ---------------------------------------------------- #ifndef _FTPLIKE_INITIALIZED ;--- Define the version number of this header file ----------------------- #define+ VERSION_FTPLIKE_IH 99.325 #require 99.325 ;--- Check prerequisites ------------------------------------------------- #ifndef FTPLIKE_DIRECTORY #error ^You must define the "FTPLIKE_DIRECTORY" value (local directory)!^ #endif #ifndef FTPLIKE_DIRECTORY_WEB #error ^You must define the "FTPLIKE_DIRECTORY_WEB" value (web location)!^ #endif ;--- Include macro push/pop support -------------------------------------- #ifndef VERSION_PUSHPOPM_H #include "PushPopM.H" #endif ;--- Use same date time on all generated pages --------------------------- #ifndef FTPLIKE_DATETIME #evaluate FTPLIKE_DATETIME @date('WeekDay') || ' ' || date('Month') || ' ' || substr(date('Sorted'), 7, 2) || ' ' || left(date('Sorted'), 4) || ' at ' || time('Civil')@ #endif ;--- Total numbers accross FTP pages ------------------------------------- #RexxVar FtpTotalDirCnt = 0 ;;Number of directories #RexxVar FtpTotalFileCnt = 0 ;;Number of files ;--- Remember the output level where it all began! ----------------------- #Rexxvar FtpStartLevel = ;--- Work out what filemasks users wants --------------------------------- #ifndef FTPLIKE_FILE_MASKS ;--- Default is to process all files ----------------------------- #if ['' = 'UNIX'] #define FTPLIKE_FILE_MASKS #else #define FTPLIKE_FILE_MASKS *.* #endif #endif #ifndef FTPLIKE_DIR_MASKS ;--- Default is to process all directories ----------------------- #if ['' = 'UNIX'] #define FTPLIKE_DIR_MASKS #else #define FTPLIKE_DIR_MASKS *.* #endif #endif ;--- Do best we can for input dependancies ------------------------------- #ifdef FTPLIKE_FOLLOW_SUBDIRECTORIES #DependsOn INPUT ^*FILES=+<$FTPLIKE_DIRECTORY><$FTPLIKE_DIR_MASKS>^ #elseif #DependsOn INPUT ^*FILES=<$FTPLIKE_DIRECTORY><$FTPLIKE_DIR_MASKS>^ #endif ;--- Allow user to easily support frames etc ----------------------------- #ifndef FTPLIKE_LINK2DIR #define FTPLIKE_LINK2DIR #endif #ifndef FTPLIKE_LINK2FILE #define FTPLIKE_LINK2FILE ;;Probably would not want to override this #endif ;--- Prepare for generating HTML page names ------------------------------ #ifdef FTPLIKE_FOLLOW_SUBDIRECTORIES ;--- Prepare for generating html page names (unique names!) ------ #evaluate '' ^call GetIdPrepare 'FTPLIKE', 'Y'^ ;--- Don't generate filename same as current "base" file! -------- #evaluate '' ^call SetId 'FTPLIKE', '', EnsureFileHasCorrectCase(_filespec('W', _filespec('Name', '')))^ #endif ;--- Now work out the output directory ----------------------------------- #evaluate+ 'FtpGenDir' ^_filespec('location', '')^ ;--- Work out the full name of this header file -------------------------- #RexxVar FtpLikeFile = '' ;--- Relative web directory ---------------------------------------------- #define _FTPLIKE_DIRECTORY_WEB_RELATIVE ;--- Work out what user wants to call the "root" dir --------------------- #ifndef FTPLIKE_DISPLAY_DIR #define FTPLIKE_DISPLAY_DIR / #endif ;--- Work out extension to use ------------------------------------------- #ifndef FTPLIKE_HTML_EXTN #define FTPLIKE_HTML_EXTN htm #endif ;--- User want specific prefix for generated filenames ------------------- #ifndef FTPLIKE_NEWHTML_PREFIX #ifdef FTPLIKE_USE_LONG_FILENAMES #define FTPLIKE_NEWHTML_PREFIX FtpLike_ #elseif #define FTPLIKE_NEWHTML_PREFIX ;;No prefix #endif #endif ;--- Define Simple HEADERS & FOOTERS ------------------------------------- #ifndef FTPLIKE_HEADER #define FTPLIKE_HEADER

{$Title}

#endif #ifndef FTPLIKE_FOOTER #define FTPLIKE_FOOTER \
%\
%\ %\ <$FTPLIKE_DATETIME> %\ %\
%\ #endif ;--- Define START OF HTML page ------------------------------------------- #ifndef FTPLIKE_EXTRA_HEAD_TAGS #define FTPLIKE_EXTRA_HEAD_TAGS #endif #ifndef FTPLIKE_BODY_TAG #define FTPLIKE_BODY_TAG #endif #ifndef FTPLIKE_START_HTML_PAGE #define FTPLIKE_START_HTML_PAGE \ %\ %\ %\ %\ <$FTPLIKE_DISPLAY_DIR> %\ <$FTPLIKE_EXTRA_HEAD_TAGS> -\ %\ <$FTPLIKE_BODY_TAG> %\ <$FTPLIKE_HEADER Title=^<$FTPLIKE_DISPLAY_DIR>^> %\ #endif ;--- Define some stubs (you can add comments like "no directories found" etc) --- #ifndef FTPLIKE_START_PAGE_AFTER_TITLE #define FTPLIKE_START_PAGE_AFTER_TITLE <$FTPLIKE_DIR_DIZ_HANDLER> #endif #ifndef FTPLIKE_BETWEEN_DIRS_AND_FILES #define FTPLIKE_BETWEEN_DIRS_AND_FILES #endif #ifndef FTPLIKE_END_PAGE_ABOVE_FOOTER #define FTPLIKE_END_PAGE_ABOVE_FOOTER #endif ;--- Define START OF files ----------------------------------------------- #ifndef FTPLIKE_BEFORE_ALL_FILES #define FTPLIKE_BEFORE_ALL_FILES \
%\ #endif #ifndef FTPLIKE_BEFORE_ALL_DIRS #define FTPLIKE_BEFORE_ALL_DIRS \
%\
#endif ;--- How to handle a directory's name ------------------------------------ #ifndef FTPLIKE_GENERATE_HTML_FOR_DIR_TREE #define FTPLIKE_GENERATE_HTML_FOR_DIR_TREE \ #evaluate+ '' "FtpOutput = _filespec('name', FtpDir)" -\ -\ ;--- Work out HTML base name ------------ -\ #ifdef FTPLIKE_USE_LONG_FILENAMES -\ #evaluate+ "FtpDirId" ^EnsureFileHasCorrectCase( GetId('FTPLIKE', '2_', '<$FTPLIKE_NEWHTML_PREFIX><$_FTPLIKE_DIRECTORY_WEB_RELATIVE $$SQx2>/' || FtpOutput) )^ -\ #elseif -\ #evaluate+ "FtpDirId" ^EnsureFileHasCorrectCase( GetId('FTPLIKE', 'MAXCHARS', '<$FTPLIKE_NEWHTML_PREFIX>' || FtpOutput) )^ -\ #endif -\ -\ ;--- Start HTML page for new dir --- -\ #output "<$FtpDirId>.<$FTPLIKE_HTML_EXTN>" -\ ;--- "PUSH" some values --- -\ <$MacroPush Macro='FTPLIKE_DIRECTORY'> -\ <$MacroPush Macro='FTPLIKE_DIRECTORY_WEB'> -\ <$MacroPush Macro='FTPLIKE_DISPLAY_DIR'> -\ <$MacroPush Macro='_FTPLIKE_DIRECTORY_WEB_RELATIVE'> -\ <$MacroPush Macro='FtpDirId'> -\ #RexxVar PUSH FtpOutput FtpDir -\ -\ ;--- Create HTML contents --- -\ #option PUSH DefineMacroReplace=ON -\ #define+ FTPLIKE_DIRECTORY <$FTPLIKE_DIRECTORY> -\ #evaluate+ FTPLIKE_DISPLAY_DIR ^ReplaceString('<$FTPLIKE_DISPLAY_DIR $$SQx2>/' || FtpOutput, '//', '/')^ -\ #define+ FTPLIKE_DIRECTORY_WEB <$FTPLIKE_DIRECTORY_WEB>/ -\ #define+ _FTPLIKE_DIRECTORY_WEB_RELATIVE <$_FTPLIKE_DIRECTORY_WEB_RELATIVE>/ -\ #option POP -\ #include "ftplike.ih" -\ -\ ;--- "POP" some values --- -\ #RexxVar POP FtpOutput FtpDir -\ <$MacroPop Macro='FtpDirId'> -\ <$MacroPop Macro='_FTPLIKE_DIRECTORY_WEB_RELATIVE'> -\ <$MacroPop Macro='FTPLIKE_DISPLAY_DIR'> -\ <$MacroPop Macro='FTPLIKE_DIRECTORY_WEB'> -\ <$MacroPop Macro='FTPLIKE_DIRECTORY'> -\ #output #endif ;--- How to handle (display) directory details --------------------------- #ifndef FTPLIKE_DIR_HANDLER #define FTPLIKE_DIR_HANDLER \ -\ -\ -\ #endif ;--- How to handle a file's name ----------------------------------------- #ifndef FTPLIKE_FILE_HANDLER #define FTPLIKE_FILE_HANDLER \ #evaluate '' ^FtpOutput = _filespec('name', FtpFile)^ -\ #evaluate '' ^eURL = UrlEncode('<$FTPLIKE_DIRECTORY_WEB>/' || FtpOutput, 'TO%', ' ')^ -\ ;;Start New File row %\ ;;End cell #endif ;--- How to handle a file's details -------------------------------------- #ifndef FTPLIKE_FILE_DETAILS_HANDLER #define FTPLIKE_FILE_DETAILS_HANDLER \ #evaluate '' ^<$FTPLIKE_FILE_ATTRIBUTE_HANDLER_REXX>^ -\ ;;End cell %\ ;;End this File row #endif ;--- Define END OF files ------------------------------------------------- #ifndef FTPLIKE_AFTER_ALL_FILES #define FTPLIKE_AFTER_ALL_FILES
-\ ;--- Link to HTML page we will create --- -\ <$FTPLIKE_LINK2DIR Url="<$FtpDirId>.<$FTPLIKE_HTML_EXTN>"> -\ ;;Just output short name -\ -\ -\ -\ -\ -\ -\ -\
dirs files
-\
;;Start filename cell %\ <$FTPLIKE_LINK2FILE Url=""> -\ ;;Just output short name -\ %\ ;;Start file details cell %\ \ ::, \ \ bytes %\ <$FTPLIKE_FILE_DIZ_HANDLER> -\
#endif #ifndef FTPLIKE_AFTER_ALL_DIRS #define FTPLIKE_AFTER_ALL_DIRS

#endif ;--- Define ATTRIBUTE Handler (date, time, size etc) --------------------- #ifndef FTPLIKE_FILE_ATTRIBUTE_HANDLER_REXX #define FTPLIKE_FILE_ATTRIBUTE_HANDLER_REXX \ FtpTimeStamp = GetFileTimeStamp(FtpFile); -\ FtpSize = stream(FtpFile, 'c', 'query size'); -\ FtpSize = AddCommasToDecimalNumber(FtpSize); -\ parse var FtpTimeStamp FtpYear +4 FtpMonth +2 FtpDay +2 FtpHour +2 FtpMinute +2 FtpSecond; -\ FtpMon = substr('JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC', ((FtpMonth-1)*4)+1, 3); #endif ;--- Process this directory? (no filter by default) ---------------------- #ifndef FTPLIKE_DO_THIS_DIR #define FTPLIKE_DO_THIS_DIR ;;Generate for all directories #endif ;--- Process this file? (by default no ".diz" files!) -------------------- #ifndef FTPLIKE_DO_THIS_FILE #define FTPLIKE_DO_THIS_FILE_REXX \ if translate(right(FtpFile, 4)) = '.diz' then; -\ FtpDoThisFile = 'N'; ;;Description file! #define FTPLIKE_DO_THIS_FILE \ #evaluate '' ^<$FTPLIKE_DO_THIS_FILE_REXX>^ #endif ;--- Define "DIZ" handler ------------------------------------------------ #ifndef FTPLIKE_FILE_DIZ_HANDLER #define FTPLIKE_FILE_DIZ_HANDLER_REXX \ FtpDizFile = stream(FtpFile || '.diz', 'c', 'query exists'); -\ if FtpDizFile = '' then; -\ do; -\ ;--- Try changing extension to ".diz" --- -\ FtpPos = lastpos('.', FtpFile); -\ if FtpPos <> 0 then; -\ FtpDizFile = stream(left(FtpFile,FtpPos) || 'DIZ', 'c', 'query exists'); -\ end; -\ if FtpDizFile = '' then; -\ FtpDiz = ''; -\ else; -\ do; -\ FtpDiz = charin(FtpDizFile, 1, 99999); -\ call DieIfIoErrorOccurred FtpDizFile; -\ CloseRc = stream(FtpDizFile, 'c', 'close'); -\ <$FTPLIKE_DIZ_TRANSLATION_REXX> -\ FtpDiz = {$Prefix=^''^} || FtpDiz || {$Suffix=^''^}; -\ end; #define FTPLIKE_FILE_DIZ_HANDLER \ #evaluate '' ^<$FTPLIKE_FILE_DIZ_HANDLER_REXX PREFIX=~'


'~>^ -\ #endif #ifndef FTPLIKE_DIR_DIZ_HANDLER #define FTPLIKE_DIR_DIZ_HANDLER \ #evaluate '' ^FtpFile = '<$FTPLIKE_DIRECTORY $$SQx2>' || _filespec('name', '<$FTPLIKE_DIRECTORY $$SQx2>')^ -\ #evaluate '' ^<$FTPLIKE_FILE_DIZ_HANDLER_REXX SUFFIX=~'
'~>^ -\ #endif ;--- Define "DIZ" translations ------------------------------------------- #ifndef FTPLIKE_DIZ_TRANSLATION_REXX #define FTPLIKE_DIZ_TRANSLATION_REXX \ FtpDiz = ReplaceString(FtpDiz, '1A'x, ''); ;;EOF char ;;;;;; FtpDiz = ReplaceString(FtpDiz, '0D0A0D0A'x, '0D0A'x || '

'); #endif ;--- Define how files are SORTED ----------------------------------------- #ifndef FTPLIKE_FILE_SORT #ifndef FTPLIKE_FILE_SORT_REXX #define FTPLIKE_FILE_SORT_REXX \ call SortArray '{$ArrayName}' #endif #define FTPLIKE_FILE_SORT \ #evaluate '' ^<$FTPLIKE_FILE_SORT_REXX ArrayName=~{$ArrayName}~>^ #endif #ifndef FTPLIKE_DIRECTORY_SORT #define FTPLIKE_DIRECTORY_SORT <$FTPLIKE_FILE_SORT ArrayName=~{$ArrayName}~> ;;Same as file sort by default #endif ;--- Make sure not done again (when a directory being processed etc) ----- #define _FTPLIKE_INITIALIZED #endif ;--- Simple processing message ---------------------------------------------- #evaluate '' ^ShortOutName = _filespec('Name', '')^ #info ^Generating <= <$FTPLIKE_DIRECTORY>^ ;--- Initialization for this FTP page --------------------------------------- #RexxVar FtpDirCnt = 0 ;;Number of directories on this html page #RexxVar FtpFileCnt = 0 ;;Number of files on this html page ;--- Generate start of HTML ------------------------------------------------- #if <> FtpStartLevel | defined('FTPLIKE_NO_HEADER_FOOTER_ON_1ST_PAGE') = 'N' <$FTPLIKE_START_HTML_PAGE> #endif <$FTPLIKE_START_PAGE_AFTER_TITLE> ;--- Process directories? (need to be careful as we include ourself) -------- #ifdef FTPLIKE_FOLLOW_SUBDIRECTORIES ;--- Get list of directories ---------------------------------------- #evaluate '' ^call _SysFileTree '<$FTPLIKE_DIRECTORY $$SQx2><$FTPLIKE_DIR_MASKS>', 'FtpArray', 'DO'^ ;--- Any directories to display? ------------------------------------ #if [FtpArray.0 <> 0] ;--- Sort the list (if thats what user wants) -------------------- <$FTPLIKE_DIRECTORY_SORT ArrayName="FtpArray"> ;--- Process DIRECTORIES ----------------------------------------- #RexxVar FtpIndex = 1 #{ ;--- Finished? ----------------------------------------------- #if [FtpIndex > FtpArray.0] #break #endif ;--- Get name of this directory ------------------------------ #RexxVar FtpDir = FtpArray.FtpIndex ;--- Generate the files -------------------------------------- #RexxVar FtpDoThisDir = 'Y' <$FTPLIKE_DO_THIS_DIR> ;;User want this dir to be seen? #if [FtpDoThisDir = 'Y'] ;--- User does want this dir to be seen ------------------ #RexxVar FtpDirCnt + 1 #if [FtpDirCnt = 1] ;--- Start DIRECTORY output -------------------------- <$FTPLIKE_BEFORE_ALL_DIRS> #endif ;--- Save some variables --------------------------------- #RexxVar PUSH FtpDirCnt FtpFileCnt FtpTotalDirCnt FtpTotalFileCnt ;--- Reset totals ---------------------------------------- #RexxVar FtpTotalDirCnt = 0 #RexxVar FtpTotalFileCnt = 0 ;--- Process all subdirectories (generating HTML as we go) <$FTPLIKE_GENERATE_HTML_FOR_DIR_TREE> ;--- Remember subdirectory counts ------------------------ #RexxVar FtpSubdirTotalFileCnt = FtpTotalFileCnt #RexxVar FtpSubdirTotalDirCnt = FtpTotalDirCnt ;--- Display directory details on this page -------------- <$FTPLIKE_DIR_HANDLER> ;--- Restore other variables ----------------------------- #RexxVar POP FtpDirCnt FtpFileCnt FtpTotalDirCnt FtpTotalFileCnt ;--- Add to totals --------------------------------------- #RexxVar FtpTotalFileCnt + FtpSubdirTotalFileCnt #RexxVar FtpTotalDirCnt + FtpSubdirTotalDirCnt #endif ;--- Prepare for next file ----------------------------------- #RexxVar FtpIndex + 1 #} ;--- Generate end DIRECTORY stuff -------------------------------- #if [FtpDirCnt <> 0] <$FTPLIKE_AFTER_ALL_DIRS> #endif #endif ;--- Hook for displaying stuff -------------------------------------- <$FTPLIKE_BETWEEN_DIRS_AND_FILES> #endif ;--- Get list of files ------------------------------------------------------ #evaluate '' ^call _SysFileTree '<$FTPLIKE_DIRECTORY $$SQx2><$FTPLIKE_FILE_MASKS>', 'FtpArray', 'FO'^ ;--- Any files in this directory? ------------------------------------------- #if [FtpArray.0 <> 0] ;--- Sort the list (if thats what user wants) ---------------------------- <$FTPLIKE_FILE_SORT ArrayName="FtpArray"> ;--- Process files ------------------------------------------------------- #RexxVar FtpIndex = 1 #{ ;--- Finished? ------------------------------------------------------- #if [FtpIndex > FtpArray.0] #break #endif ;--- Get Filename ---------------------------------------------------- #RexxVar FtpFile = FtpArray.FtpIndex ;--- Generate the files ---------------------------------------------- #RexxVar FtpDoThisFile = 'Y' <$FTPLIKE_DO_THIS_FILE> ;;User want this file to be seen? #if [FtpDoThisFile = 'Y'] ;--- User does want this file to be seen ------------------------- #RexxVar FtpFileCnt + 1 #if [FtpFileCnt = 1] ;--- Start FILE output --------------------------------------- <$FTPLIKE_BEFORE_ALL_FILES> #endif ;--- Output details for this file -------------------------------- <$FTPLIKE_FILE_HANDLER> <$FTPLIKE_FILE_DETAILS_HANDLER> #endif ;--- Prepare for next file ------------------------------------------- #RexxVar FtpIndex + 1 #} ;--- Generate end FILES stuff -------------------------------------------- #if [FtpFileCnt <> 0] <$FTPLIKE_AFTER_ALL_FILES> #endif #endif ;--- Generate END of HTML --------------------------------------------------- <$FTPLIKE_END_PAGE_ABOVE_FOOTER> #if <> FtpStartLevel | defined('FTPLIKE_NO_HEADER_FOOTER_ON_1ST_PAGE') = 'N' ;--- User has not set up their own alternative ----------------------- <$FTPLIKE_FOOTER> ;;Footer ends body and html #endif ;--- Update totals ---------------------------------------------------------- #RexxVar FtpTotalFileCnt + FtpFileCnt #RexxVar FtpTotalDirCnt + FtpDirCnt ;--- Output summary --------------------------------------------------------- #if [ = FtpStartLevel] #ifndef FTPLIKE_FOLLOW_SUBDIRECTORIES #info ^FTPLIKE processed file(s)^ #elseif #info ^FTPLIKE processed file(s) in directories^ #endif #endif ═══ 9.2. HTMLPRE.IH - Converts Example Code to HTML ═══ HTMLPRE.IH - Converts Example Code to HTML The following example shows how text can be included from a file. The included text is displayed using the html "

" tag and automates a complex, time 
consuming and error prone task. 

Characters such as  "<" are converted to "<" so that the lines will 
correctly display in a browser.  The example will also show how keywords can be 
linked to a glossary or page which explains a concept. Two international 
symbols are also handled for demonstration purposes: 

    ;--- Include header for example support -------------------------------------
    #include "HTMLPRE.IH"

    ;--- Set up all international characters we will handle ---------------------
    #AutoTagState +
    #AutoTag      'Д'    'ä'
    #AutoTag      'Й'    'ë'
    #AsIs         SETUP  INTERNATIONAL_SYMBOLS
    #AutoTagState -

    ;--- Some HTML text ---------------------------------------------------------
    

The following is the contents of my "config.sys" file: ;--- Include the example ---------------------------------------------------- #AutoTagState + ;;Lets not affect any existing tagging #AutoTag "REM " "REM " ;;Define a single change <$ExampleFile FILE="E:\CONFIG.SYS" STATE=REMEMBER ASIS=INTERNATIONAL_SYMBOLS> #AutoTagState - ;;Restore original tagging state HTMLPRE.IH This shows the contents of the header file (supplied with PPWIZARD) that provides HTML example support: ;---------------------------------------------------------------------------- ; MODULE NAME: HTMLPRE.IH ; ; $Author: Dennis_Bareis $ ; $Revision: 1.2 $ ; $Date: 20 Nov 1999 08:11:24 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/HTMLPRE.IHV $ ; ; DESCRIPTION: This is a header file for handling inclusion of ; "examples" into HTML. ; ; See PPWIZARD documentation for examples of this file ; in use. The sample "TryMe.IT" file also uses this ; header file. ; ; ; Macro "ExampleFile" ; ~~~~~~~~~~~~~~~~~~~ ; ; This macro takes the following parameters: ; ; FILE ; ~~~~ ; Manditory. Identifies the file to be included. ; ; FRAGMENT ; ~~~~~~~~ ; Optional. You may wish to have a single example ; file hold more than one example. The text that ; you supply for this parameter marks the line before ; as well as the line after the example. ; ; ; INDENT ; ~~~~~~ ; Optional. By default a 4 space indent is used, ; you specify the number of spaces with 0 being ; valid. ; ; STATE ; ~~~~~ ; Optional. By default no autotagging will be ; performed. If you specify "REMEMBER" then the ; currently available autotags will be used, you ; may also specify which states tags should come ; from (see the "#AutoTagState +" command). ; ; ; ASIS ; ~~~~ ; Optional. By default only basic "AsIs" tagging ; is performed. If for example you wished to ; handle international characters then you would ; need to specify the names of the AsIs tags to use. ; ; ; ; Macro "Example / eExample" ; ~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ; Note that your "inline" example code must not contain ; a reference to the macro "eExample" as this is used ; internally. ; ; This macro takes the following parameters: ; ; ; INDENT ; ~~~~~~ ; As above. ; ; STATE ; ~~~~~ ; As above. ; ; ; ASIS ; ~~~~ ; As above. ; ; ; ;---------------------------------------------------------------------------- ;--- Define the version number of this header file -------------------------- #define VERSION_HTMLPRE_IH 99.322 #require 99.265 ;---------------------------------------------------------------------------- ;--- Set up defaults that user can override --------------------------------- ;---------------------------------------------------------------------------- #ifndef HTMLPRE_COLOR #define HTMLPRE_COLOR purple #endif #ifndef HTMLPRE_STYLE_OTHER #define HTMLPRE_STYLE_OTHER ;font-size:80% #endif ;--- Define some aliases for characters we need to be careful with ---------- #RexxVar "LT" =x= "<" ;;'<' Char #RexxVar "GT" =x= ">" ;;'>' Char #RexxVar "AMP" =x= "&" ;;'&' Char #RexxVar "HASH" =x= "#" ;;'#' Char ;--- Define look and feel of examples --------------------------------------- #define ExampleFormatted \ > ;;Set up font (older browsers) -\

#define eExampleFormatted                                                                           \
        
-\ ;;Restore Font (older browsers) ;--- Set up AsIs Mode (minimum changes required - user can add to these) ---- #AutoTagState + ;--- Define characters that should be automatically modified ------------- #AutoTag "<" "" #AutoTag ">" "" #AutoTag "&" "" #AutoTag "#" "" ;--- "PROGRAM" ASIS mode ------------------------------------------------- #AsIs SETUP HTMLPRE_IH #AutoTagState - ;---------------------------------------------------------------------------- ;--- ALLOW SPELL CHECKING IN EXAMPLES? -------------------------------------- ;---------------------------------------------------------------------------- #ifndef HTMLPRE_SPELL_CHECKING #define HTMLPRE_SPELL_CHECKING OFF #endif ;---------------------------------------------------------------------------- ;--- EXAMPLE FILE INCLUSION ------------------------------------------------- ;---------------------------------------------------------------------------- #define ExampleFile \ <$ExampleFormatted> -\ #AutoTagState + {$STATE=''} ;;User can set up own tags -\ #option PUSH AllowSpell={$SPELL="<$HTMLPRE_SPELL_CHECKING>"} ExtraIndent=^copies(' ', {$Indent='4'})^ -\ #AutoTag ON -\ #AsIs ON HTMLPRE_IH {$AsIs=''} -\ #include "{$File}" "{$Fragment=''}" -\ #AsIs OFF -\ #option POP -\ #AutoTagState - -\ <$eExampleFormatted> ;---------------------------------------------------------------------------- ;--- EXAMPLE (INLINE) ------------------------------------------------------- ;---------------------------------------------------------------------------- #define Example ;;Starts Example \ <$ExampleFormatted> -\ #AutoTagState + {$STATE=''} ;;User can set up own tags -\ #option PUSH AllowSpell={$SPELL="<$HTMLPRE_SPELL_CHECKING>"} ExtraIndent=^copies(' ', {$Indent='4'})^ -\ #option PUSH replace=OFF -\ #AutoTag '$eExample' '<$eExample>' #1 -\ #option POP ;;Restore REPLACE mode -\ #AutoTag ON -\ #AsIs ON HTMLPRE_IH {$AsIs=''} -\ #define HTMLPRE_INLINE_EXAMPLE #define eExample ;;Ends Example \ #ifndef HTMLPRE_INLINE_EXAMPLE -\ #error ^Incorrectly formatted inline example (can't include end of example tag)^ -\ #endif -\ #AsIs OFF -\ #option POP -\ #AutoTagState - -\ #undef HTMLPRE_INLINE_EXAMPLE -\ <$eExampleFormatted> ═══ 9.3. NESTCHK.H - Nesting Validation ═══ NESTCHK.H - Nesting Validation The following example shows how validation of the nesting of HTML (or other language) tags can be performed. The Netscape browser will not display a table (or other components) that does not have a matching end tag. This is a common cause of blank pages (or missing information). Rather than hope your comprehensive testing picks up this fact (missing information or faulty layout may not always be obvious) you can ensure that the problem is reported at development time. Note that "NESTCHK.H" contains generic routines so it simplifies your task to "front end" some of the macros with your own. To ensure that you never forget to perform the checking its wise to always end your html with something that is required on your page such as a standard footer. The following code shows how a standard header file of yours (lets call it "MYHEADER.IH") might incorporate nesting checking (example only shows "TABLE" being validated): ;--- Include generic nesting validation header file ------------------------- #include "nestchk.h" ;--- Define what we are checking (table tags only here) --------------------- <$NestingInit Id="TABLE" DESC="HTML TABLE tags"> #define TABLE <$NestingInc Id="TABLE">TABLE #define /TABLE <$NestingDec Id="TABLE"> The following is a HTML page of yours that will fail the validation: ;--- Include Common header -------------------------------------------------- #include "MYHEADER.IH" ;--- Start HTML (some of this might be better in common header above!) ------ #define Title Simple html with 2 missing end of table tags <$Title>

<$Title>

Hi there... ;--- Incorrectly nested tables follow --------------------------------------- <<$TABLE> BORDER=1> <<$TABLE> BORDER=2> <<$TABLE> BORDER=3> <$/TABLE> ;;Only "remember" to end 1 of the 3 tables! ;--- End of HTML ------------------------------------------------------------ <$StandardFooter> The following shows part of the error details being displayed: * Processing: E:\DB\PROJECTS\OS2\ppwizard\1.in NESTING ERRORS ~~~~~~~~~~~~~~ Missing 2 end nesting tags on "HTML TABLE tags" * line 46 of "E:\DB\PROJECTS\OS2\ppwizard\1.in" <<$TABLE> BORDER=1> * line 47 of "E:\DB\PROJECTS\OS2\ppwizard\1.in" <<$TABLE> BORDER=2> NESTCHK.H This shows the contents of the header file (supplied with PPWIZARD) that provides the generic nesting support: ;---------------------------------------------------------------------------- ; MODULE NAME: NESTCHK.H ; ; $Author: Dennis_Bareis $ ; $Revision: 1.4 $ ; $Date: 13 Nov 1999 13:39:22 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/NESTCHK.H_V $ ; ; REQUIRES: Regina 0.08f onwards, or you get clause length problems. ; ; DESCRIPTION: This is a header file for generic handling of ; nesting checking. This is where you must have matching ; "whatevers" such as a matching "" for a ; "" etc. ; ; "TABLE" checking is a good example as are "FRAMESET" ; statements as the Netscape browser will not display ; an incorrectly nested page (common cause of "blank" ; pages). This header file can be used to detect these ; errors while still developing the pages rather than ; HOPING that testing will show up the errors. ; ; Because these macros are generic you would usually have ; your own header file to front end them, for example your ; header could begin with: ; ; ;--- Prepare table nesting checking code --- ; #include "NESTCHK.H" ; <$NestingInit Id="HTMLTAG_TABLE" DESC="HTML TABLE tag"> ; #define TABLE \ ; -\ ; <$NestingInc Id="HTMLTAG_TABLE"> ; #define /TABLE \ ;
-\ ; <$NestingDec Id="HTMLTAG_TABLE"> ; ; Your code would then always use the table macros defined ; above rather than the HTML table tags directly, example: ; ; <$TABLE BORDER=5 CELLPADDING=10> ; ;;Could validate TD /TD etc! ; ... ; ; <$/TABLE> ; ; You would probably do more that just "TABLE" tags in the ; above example! Notice that the only difference in your ; actual code is an extra '$'! ; ; Macro "HtmlNesting" ; ~~~~~~~~~~~~~~~~~~~ ; ; This header file now allows easy creation of macros such ; as the "TABLE" and "/TABLE" shown above. For example to ; create nest checking macros for "TABLE", "/TABLE", "TH", ; "/TH", "TD" and "/TD" you would use: ; ; <$HtmlNesting TAG="TABLE"> ; <$HtmlNesting TAG="TH"> ; <$HtmlNesting TAG="TD"> ; ; ; Macro "NestingInit" ; ~~~~~~~~~~~~~~~~~~~ ; ; This macro takes the following parameters: ; ; ID ; ~~ ; Manditory. Short name to describe what we wish ; to check. Must contain only characters which ; are valid in rexx variable names (no checking of ; this is done). ; ; DESC ; ~~~~ ; A description which is displayed if a nesting ; error is found. ; ; ; Macro "NestingInc" ; ~~~~~~~~~~~~~~~~~~ ; ; This macro takes the following parameters: ; ; ID ; ~~ ; Manditory. Matches that used on "NestingInit". ; You are increasing the level of nesting. ; ; ; Macro "NestingDec" ; ~~~~~~~~~~~~~~~~~~ ; ; This macro takes the following parameters: ; ; ID ; ~~ ; Manditory. Matches that used on "NestingInit". ; You are decreasing the level of nesting. ; ; ; Macro "NestingLevel" ; ~~~~~~~~~~~~~~~~~~~ ; ; This macro takes the following parameters: ; ; ID ; ~~ ; Manditory. Matches that used on "NestingInit". ; Returns the name of the variable which contains ; the level (0= neutral, 1 = down one etc). ; ;---------------------------------------------------------------------------- ;--- Only include this header once! ----------------------------------------- #ifndef VERSION_NESTCHK_H ;--- Define the version number of this header file -------------------------- #define VERSION_NESTCHK_H 99.317 #require 99.317 ;--- Register checking macro ------------------------------------------------ #OnExit <$NestingCheck> ;--- Currently not tracking nesting of anything ----------------------------- #RexxVar NestingIdCount = 0 ;--- Define macro to keep track of items ------------------------------------ #DefineRexx NestingInit_REXX ;--- Ensure ID is valid (needs to be valid rexx var format) ----- if symbol('{$ID $$SQx2}') = 'BAD' then Error('The ID of "{$ID $$SQx2}" contains invalid characters!', 'It must be in the format of a valid rexx variable name'); if symbol('{$ID $$SQx2}_Level') = 'VAR' then Error('The ID of "{$ID $$SQx2}" has already been initialized!'); ;--- Remember ID details -------------------------- NestingIdCount = NestingIdCount + 1; call _valueS "NESTINGID.NestingIdCount.ID", '{$ID $$SQx2}'; call _valueS "NESTINGID.NestingIdCount.DESC", '{$DESC}'; call _valueS "{$ID $$SQx2}_DESC", '{$DESC}'; ;--- Initialize level counter --------------------- call _valueS '{$ID $$SQx2}_Level', 0; #DefineRexx #define NestingInit \ #evaluate '' ^<$NestingInit_REXX ID='{$ID}' DESC='{$DESC}'>^ ;--- We are going down one level of nesting --------------------------------- ; [SaveSourceAndLocnInfo] (Ignore this - this bit used to include section into doco) #DefineRexx NestingInc_REXX ;--- Ensure ID is valid ------- if symbol('{$ID $$SQx2}_Level') <> 'VAR' then Error('The ID of "{$ID $$SQx2}" is unknown (you must use "NestingInit")!'); ;--- Increase nesting level --- call _valueS "{$ID}_Level", {$ID}_Level + 1; ;--- Record details about current location --- call _valueS "{$ID}_FilePosn.{$ID}_Level", GetInputFileNameAndLine(); call _valueS "{$ID}_CurrLine.{$ID}_Level", GetFileLineBeingProcessed(); #DefineRexx #define NestingInc \ #evaluate '' ^<$NestingInc_REXX ID='{$ID}'>^ ; [SaveSourceAndLocnInfo] (Ignore this - this bit used to include section into doco) ;--- We are going up one level of nesting ----------------------------------- #DefineRexx NestingDec_REXX ;--- Ensure ID is valid ------- if symbol('{$ID $$SQx2}_Level') <> 'VAR' then Error('The ID of "{$ID $$SQx2}" is unknown (you must use "NestingInit")!'); ;--- Decrease nesting level --- NewLevel = {$ID}_Level - {$DecreaseBy="1"}; if NewLevel < 0 then call Error "Too many end tags for " || {$ID}_DESC; ;--- Record updated details --- call _valueS "{$ID}_Level", NewLevel; #DefineRexx #define NestingDec \ #evaluate '' ^<$NestingDec_REXX ID='{$ID}' {$?}>^ ;--- Allow user to access the counter variable ------------------------------ #define NestingLevel \ {$ID}_Level ;--- Check nesting of all ID's ---------------------------------------------- #DefineRexx NestingCheck_REXX ;--- Loop though all registered "nesting" items --- NestingError = 0; ;;No errors found yet do CheckIndex = 1 to NestingIdCount; ;--- Get basic information about item --- _ID = NESTINGID.CheckIndex.ID; _DESC = NESTINGID.CheckIndex.DESC; _Level = _valueG(_ID || "_Level"); if _Level <> 0 then; do; if NestingError = 0 then; do; say ''; say 'NESTING ERRORS'; say '~~~~~~~~~~~~~~'; end; NestingError = NestingError + 1; if _Level < 0 then; say 'Have ' || abs(_Level) || ' too many end nesting tags on "' || _DESC || '"'; else; do; ;--- display nesting info --- say 'Missing ' || _Level || ' end nesting tag(s) on "' || _DESC || '"'; do _ThisLevel = 1 to _Level; say ' * ' || _valueG(_ID || "_FilePosn._ThisLevel"); say ' ' || _valueG(_ID || "_CurrLine._ThisLevel"); end; end; end; end; #DefineRexx #define NestingCheck \ #evaluate '' ^<$NestingCheck_REXX>^ \ #if [NestingError <> 0] \ #error ^NestingCheck(): Found nesting error(s) as described above^ \ #endif ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ;%%%[ The following macros allow you to easily define HTML tag Nesting ]%%% ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ;--- This is the only tag of the following you should use! ---------------- #define HtmlNesting \ ;--- Initialization for this tag --- -\ <$NestingInit Id="HTML_{$TAG}" \ DESC='HTML {$TAG} tag nesting' -\ > -\ -\ #evaluate ^^ ^<$REXX_HTML_NESTING TAG=^{$TAG}^ Type="Inc">^ -\ #evaluate ^^ ^<$REXX_HTML_NESTING TAG=^{$TAG}^ Type="Dec">^ ;--- Define GENERIC macros for TAG and /TAG (use pseudo parameters) ------- #define _HTML_NESTING_Inc \ [Tag]{$?}> -\ <$NestingInc Id="HTML_[Tag]"> #define _HTML_NESTING_Dec \ -\ <$NestingDec Id="HTML_[Tag]"> ;--- Define code which creates TAG start/end macros ----------------------- #DefineRexx REXX_HTML_NESTING ;--- Get GENERIC Macro (START or END) --- TagMacro = MacroGet('_HTML_NESTING_{$Type}'); ;--- Replace pseudo parameters --- TagMacro = ReplaceString(TagMacro, '[Tag]', '{$TAG $$SQx2}'); ;--- Create START or END html tag macro --- if '{$Type}' = 'Inc' then HtmlTag = '{$TAG $$SQx2}'; else HtmlTag = '/{$TAG $$SQx2}'; call MacroSet HtmlTag, TagMacro; #DefineRexx ;--- Only include this header once! ----------------------------------------- #endif ═══ 9.4. VALRURL.H - Remote Resource Validation ═══ VALRURL.H - Remote Resource Validation This section describes how PPWIZARD can be used to validate remote resources, by remote I mean any resource that you could not determine if it existed or not purely by examining the local machines environment. The header file "VALRURL.H" can be used to validate ftp and http URLs on remote servers. This will for example warn you if a particular link would generate a 404 in a browser. Currently the header works under OS/2, http (web page) validation may work as is under Windows (95/98/NT) or may require small changes. If you have another operating system you may still wish to examine the header file as only minor work would probably be required to get it to work if you already have a method to validate a URL. EXAMPLE - Immediate Validation This example is not real life in that the URLs would normally not be used on their own but would be part of a hypertext link. You are expected to be online (to the internet) at the time you try the example as the URL checking is done immediately after a otherwise successful build. The example also demonstates setting up debugging: ;--- Load external URL validation support --- ;;#define VALRURL_NO_CHECK_HTTP ;;#define VALRURL_NO_CHECK_FTP #define VALRURL_FTP_EMAIL db0@anz.com #define VALRURL_DEBUG +out\DEBUG.URL\*.DBG ;;Append to end of any existing debug file #include "VALRURL.H" ;--- Check some HTTP URLS --- <$RemHttp url="http://anz.com"> ;;Does not exist <$RemHttp url="http://www.labyrinth.net.au/~dbareis/ppwizard.htm"> ;;Exists <$RemHttp url="http://www.labyrinth.net.au/~dbareis/zips_fw"> ;;Needs a '/' <$RemHttp url="http://www.labyrinth.net.au/~dbareis/no_such.htm"> ;;Does not exist ;--- Check some FTP URLS --- <$RemFtp url="ftp://ftp.anz.com"> ;;Does not exist <$RemFtp url="ftp://ftp.pc.ibm.com/pub/pccbbs/os2_ews"> ;;Directory <$RemFtp url="ftp://ftp.pc.ibm.com/pub/pccbbs/os2_ews/aping.txt"> ;;File EXAMPLE - Delayed Validation This example is more real life. It also creates a URL list so that you don't need to be online when the html is built. You can run the generated URL files through the validator (supplied with ppwizard for OS/2 - http may work under windows) whenever you wish. It shows one possible way of defining a common header file containing a useful front end macro as well as the definition of a remote URL. As the URL is only mentioned in one place no matter where or how many times it appears on your web pages it is simple to fix if it becomes out of date. The common header file "MyCommon.IH" follows: ;--- Load external URL validation support ----------- #define VALRURL_FTP_EMAIL db0@anz.com #define VALRURL_CHECK_LATER_MASK out\REMOTE.URL\*.URL #include "VALRURL.H" ;--- Useful macro: Validate URL and generate link --- #define InternetLink \ -\ {$VISIBLE=^{$URL}^} -\ ;--- Define URLs (usually in common header file ----- #define HttpPpwizardHomePage \ http://www.labyrinth.net.au/~dbareis/ppwizard.htm What might appear in one of your pages follows: ;--- Load common header file --- #include "MyCommon.IH" ;--- Check some HTTP URLS ------

Please see my <$InternetLink URL="<$HttpPpwizardHomePage>"> for a great <$InternetLink URL="<$HttpPpwizardHomePage>" VISIBLE=^preprocessor^>. At some future stage when you are online to the internet you might start the validation process with a command similar to: ppwcurl.cmd CheckListedUrls remote.url\*.URL VALRURL.H ;---------------------------------------------------------------------------- ; MODULE NAME: VALRURL.IH ; ; $Author: Dennis_Bareis $ ; $Revision: 1.7 $ ; $Date: 20 Nov 1999 08:12:12 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/VALRURL.H_V $ ; ; DESCRIPTION: This is a header file for checking HTTP/FTP urls on ; remote servers. All URLs are passed with a leading ; "http://' or "ftp://". ; ; This routine does not validate that any "#Section" ; on http URLs are correct. It will validate that the ; html page exists on the server. ; ; It will only check a URL once. This is the case even ; across builds of multiple ".IT" files if they are being ; built using the one call to PPWIZARD. ; ; Note that I don't search a table to work out if a URL ; has already been used, my method is much faster however ; on very long URLs which appear in multiple files in the ; same PPWIZARD invokation it may repeat the test. ; ; ; OPERATING SYSTEMS ; ~~~~~~~~~~~~~~~~~ ; This header has only been tested under OS/2. The ; required DLLs appear to have been installed by OS/2 ; version 4 (Merlin). If these are unavailable on your ; machine you may need a TCP-IP fixpack, otherwise you ; will need to locate a web page containing the files. ; ; Since there is a "RxSock.DLL" available for windows ; http checking will also work there (if any changes ; required please let me know the details). ; There is no "RxFtp.DLL" for windows (that I know of). ; ; You can get RxSock for windows from: ; ; http://home.hiwaay.net/~abbott/regina/ ; ; ; COMMENTS ; ~~~~~~~~ ; Error messages could be improved a bit! ; ; Not sure about all error handling, please let me know ; of any issues you have. If you can see that I'm doing ; something wrong, please tell me! ; ; ; EXAMPLE ; ~~~~~~~ ; ;;#define VALRURL_NO_CHECK_HTTP ; ;;#define VALRURL_NO_CHECK_FTP ; ;;#define VALRURL_DEBUG out\DEBUG.URL\*.DBG ; #define VALRURL_CHECK_LATER_MASK out\REMOTE.URL\*.URL ; #define VALRURL_FTP_EMAIL db0@anz.com ; #include "VALRURL.H" ; ;

Please see ; "> ; PPWIZARD's homepage ; . ; ; You may wish to come up with your own set of "front end" ; macros to simplify the above. Also in general I recommend ; defining the external URL's in a header if they are to ; be used in more than one place. ;---------------------------------------------------------------------------- ;--- Initialization (for this compile) -------------------------------------- #ifdef VALRURL_CHECK_LATER_MASK #DefineRexx '' ;--- Create URL file name based on input name --- UrlListFile = GenerateFileName('', '<$VALRURL_CHECK_LATER_MASK>'); ;--- Delete the file for starters, will get created if any URLs --- call stream UrlListFile, 'c', 'close'; call _SysFileDelete UrlListFile; #DefineRexx #endif ;--- Only do rest of header once! ------------------------------------------- #ifndef VERSION_VALRURL_IH ;--- Define the version number of this header file ----------------------- #define VERSION_VALRURL_IH 99.315 #require 99.315 ;--- Need access to sort stuff ------------------------------------------ #include "PPWSORT.H" ;--- Allow user to prevent generation if they only wish validation ------ #ifndef RemHttpGenerate #define RemHttpGenerate {$URL} #endif #ifndef RemFtpGenerate #define RemFtpGenerate {$URL} #endif ;--- Allow user to modify what happens on failing validation ------------ #ifndef VALRURL_FAILED_VALIDATION_REXX #DefineRexx VALRURL_FAILED_VALIDATION_REXX call warning "CRURL", ThisUrl || ' ==> ' || UrlChkRc; #DefineRexx #endif ;--- Allow user to modify what happens on successful validation --------- #ifndef VALRURL_VALIDATED_OK_REXX ;--- Default is display success only when debug is on ----------- #ifdef VALRURL_DEBUG ;--- Display successful URL as debug is on -------------- #DefineRexx VALRURL_VALIDATED_OK_REXX call info 'DEBUG: ' || ThisUrl || ' successfully validated'; #DefineRexx #elseif ;--- Define empty handler if debug is off --------------- #define VALRURL_VALIDATED_OK_REXX #endif #endif ;--- Allow user to specify email address for FTP site logon ------------- #ifndef VALRURL_FTP_EMAIL #define VALRURL_FTP_EMAIL VALRURL_<$VERSION_VALRURL_IH>@real.email.address.unknown #endif ;--- User calls these macros to perform validation ---------------------- #define RemHttp \ <$ValidateHttpR URL="{$URL}"> ;;Check Remote URL -\ <$RemHttpGenerate URL="{$URL}"> ;;Generate URL #define RemFtp \ <$ValidateFtpR URL="{$URL}"> ;;Check Remote URL -\ <$RemHttpGenerate URL="{$URL}"> ;;Generate URL ;--- Checking HTTP:// ? ------------------------------------------------- #ifdef VALRURL_NO_CHECK_HTTP #define ValidateHttpR ;;No checking #elseif #define ValidateHttpR <$ValidateUrlR Type="http://" URL="{$URL}"> #endif ;--- Checking FTP:// ? -------------------------------------------------- #ifdef VALRURL_NO_CHECK_FTP #define ValidateFtpR ;;No checking #elseif #define ValidateFtpR <$ValidateUrlR Type="ftp://" URL="{$URL}"> #endif ;--- Initialization - Once per PPWIZARD Invokation (NOT build!) --------- #if symbol('UrlCheckerPgm') <> 'VAR' ;--- No need to do anything if delaying the checking! --------------- #ifndef VALRURL_CHECK_LATER_MASK #if Defined('VALRURL_NO_CHECK_HTTP') = 'N' | Defined('VALRURL_NO_CHECK_FTP') = 'N' ;--- Find External program ---------------------------------- #define VALRURL_EXT_CMD PPWCURL.CMD #evaluate '' \ ^ \ UrlCheckerPgm = _SysSearchPath('PATH', '<$VALRURL_EXT_CMD>'); \ if UrlCheckerPgm = '' then; \ do; \ parse source . . PpwRexxFile; \ UrlCheckerPgm = _filespec('location', PpwRexxFile) || '<$VALRURL_EXT_CMD>'; \ if stream(UrlCheckerPgm, 'c', 'query exists') = '' then; \ Error('Could not locate "<$VALRURL_EXT_CMD>" (searched PATH and PPWIZARD directory)'); \ end; \ ^ ;--- Display version numbers of DLLs we are using ----------- #evaluate '' ^interpret 'ExtCmdVersion = ""("VERSION?")'^ #info 'Header file version <$VERSION_VALRURL_IH>' #info 'Using Check URL external command ' #ifndef VALRURL_NO_CHECK_HTTP #evaluate '' ^interpret 'SocketVersion = ""("SOCKETVERSION?")'^ #info 'Validating remote http URLs with ' #endif #ifndef VALRURL_NO_CHECK_FTP #evaluate '' ^interpret 'FtpVersion = ""("FTPVERSION?")'^ #info 'Validating remote ftp URLs with ' #endif ;--- Set email address for FTP downloads -------------------- #ifndef VALRURL_NO_CHECK_FTP #evaluate '' ^call SetEnv "PPWCURL_EMAIL", "<$VALRURL_FTP_EMAIL>"^ #endif #endif #endif #endif ;--- Set up debug? ---------------------------------------------- #ifndef VALRURL_DEBUG #evaluate '' ^call SetEnv "PPWCURL_DEBUG", ''^ ;;Prevent Debug #elseif #evaluate '' ^TDbgFile = GenerateFileName('', '<$VALRURL_DEBUG>')^ #evaluate '' ^call _SysFileDelete TDbgFile^ #evaluate '' ^call SetEnv "PPWCURL_DEBUG", TDbgFile^ ;;Turn it on #info 'Any debugger output goes to ""' #endif ;--- Make sure we have required support for this compile ----------------- #ifndef VALRURL_CHECK_LATER_MASK #ifndef VALRURL_NO_CHECK_HTTP #evaluate '' ^interpret 'SupportHttp = ""("SOCKETREADY?")'^ #if SupportHttp <> 'OK' ;--- Can't validate HTTP URLs ----------------------------------- #Warning "CRURL" "Can't validate HTTP URLs" #define+ RemHttp <$RemHttpGenerate URL="{$URL}"> ;;Can't validate URL #endif #endif #ifndef VALRURL_NO_CHECK_FTP #evaluate '' ^interpret 'SupportFtp = ""("FTPREADY?")'^ #if SupportFtp <> 'OK' ;--- Can't validate FTP URLs ----------------------------------- #Warning "CRURL" "Can't validate FTP URLs" #define+ RemFtp <$RemFtpGenerate URL="{$URL}"> ;;Can't validate URL #endif #endif #endif ;--- Initialization for this build --------------------------------------- #RexxVar ValUrlCount = 0 ;;Counts elements in URL array #OnExit <$ProcessRemoteUrlList> ;;Handle the list (user could override macro) ;--- Handle URL (just add to array, don't worry about duplicates here) --- #define ValidateUrlR \ ;--- Make sure we validate a full URL ------------- -\ #evaluate '' ^<$ValidateUrlR_REXX_FullUrl Type="{$Type}" URL="{$URL}">^ -\ -\ ;--- Add URL (in "FullUrl" var) to end of array --- -\ #RexxVar ValUrlCount + 1 -\ #RexxVar ValUtlList.ValUrlCount = FullUrl -\ -\ ;--- Add location --------------------------------- -\ #evaluate '' ^<$ValidateUrlR_REXX_Location>^ -\ #RexxVar ValUtlLocn.ValUrlCount = UrlSourceLocation #DefineRexx ValidateUrlR_REXX_FullUrl ;--- Make sure URL starts with "http:" etc --- UrlType = "{$Type}"; FullUrl = "{$URL}"; if abbrev(FullUrl, UrlType) = 0 then; FullUrl = UrlType || FullUrl; ;--- Remove any "#section" bit --- #Option PUSH AllowPack=NO parse var FullUrl (UrlType) httpServer '/' HttpPageAddr; #Option POP parse var HttpPageAddr HttpPageAddr '#'; FullUrl = UrlType || httpServer || '/' || HttpPageAddr; #DefineRexx #ifndef ValidateUrlR_REXX_Location ;;Allow caller to create their own "location" #DefineRexx ValidateUrlR_REXX_Location #Option PUSH AllowPack=NO do IncIndex = 1 to #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 #endif ;--- Work though URL list and end of successful build -------------------- #define ProcessRemoteUrlList \ #if [ValUrlCount = 0] -\ #info 'No remote URLs to validate' -\ #elseif -\ #info 'Validating remote URLs' -\ ;--- Sort the array --- -\ #RexxVar ValUtlList.0 = ValUrlCount -\ #evaluate '' ^<$GenRexx2Sort2Arrays ARRAY1='ValUtlList' ARRAY2='ValUtlLocn'>^ -\ -\ ;--- Process the array --- -\ #evaluate '' ^<$ProcessRemoteUrlList_REXX>^ -\ #endif #DefineRexx ProcessRemoteUrlList_REXX_COMMON_START ;--- Work through URL list (drop duplicates) --- LastUrl = ''; LastLoc = ''; do UrlIndex = 1 to ValUtlList.0 ThisUrl = ValUtlList.UrlIndex; ThisLoc = ValUtlLocn.UrlIndex; if ThisUrl <> LastUrl | ThisLoc <> LastLoc then; do #DefineRexx #DefineRexx ProcessRemoteUrlList_REXX_COMMON_END LastUrl = ThisUrl; LastLoc = ThisLoc; end; end; #DefineRexx ;--- What are we doing with the list of URLs? ---------------------------- #ifndef ProcessRemoteUrlList_REXX #ifdef VALRURL_CHECK_LATER_MASK ;--- Generate file (user will check URLs later / when online) ---- #DefineRexx ProcessRemoteUrlList_REXX ;--- We already know URL filename & its been deleted --- call Info 'Generating: ' || UrlListFile; call lineout UrlListFile, ';---'; call lineout UrlListFile, ';--- Remote URLs from ""'; call lineout UrlListFile, ';--- Use PPWCURL.CMD under OS/2 or other similar'; call lineout UrlListFile, ';--- tool to process the list.'; call lineout UrlListFile, ';---'; call lineout UrlListFile, ''; call lineout UrlListFile, ''; ;--- Now work through the list of URLs --- <$ProcessRemoteUrlList_REXX_COMMON_START>; ;--- Need to output new location pragma? --- if ThisLoc <> LastLoc then call lineout UrlListFile, ';PRAGMA(URL_SOURCE)=' || ThisLoc; call lineout UrlListFile, ThisUrl; <$ProcessRemoteUrlList_REXX_COMMON_END>; ;--- Close the listing file --- call DieIfIoErrorOccurred UrlListFile; CloseRc = stream(UrlListFile, 'c', 'close'); #DefineRexx #elseif ;--- We are online, do immediate check of URLs ------------------- #DefineRexx ProcessRemoteUrlList_REXX <$ProcessRemoteUrlList_REXX_COMMON_START>; ;--- Calculate ID for this URL --- FullPageId = '!R_' || c2x(ThisUrl); FullPageIdStat = symbol(FullPageId); ;;Exists/Name too long? ;--- Already done this URL (previous build)? --- if FullPageIdStat = 'VAR' then; UrlChkRc = _valueG(FullPageId); ;;Already know if valid! else; do; ;--- Haven't checked yet --- interpret 'UrlChkRc = ""("CHECK1URL " || ThisUrl)'; ;--- Set ID so we won't repeat this exercise! --- if FullPageIdStat <> 'BAD' then; call _valueS FullPageId, UrlChkRc; end; ;--- Handle return code --- if UrlChkRc = 'OK' then; do; <$VALRURL_VALIDATED_OK_REXX>; end; else; do; <$VALRURL_FAILED_VALIDATION_REXX>; end; <$ProcessRemoteUrlList_REXX_COMMON_END>; #DefineRexx #endif #endif #endif ═══ 9.4.1. PPWCURL.CMD - Program to Check URLS (Windows and OS/2) ═══ PPWCURL.CMD - Program to Check URLS (Windows and OS/2) This program's basic task is to check URLs in an attempt to eliminate 404 errors etc from your web pages. The "VALRURL.H" header file macros is one way that URL lists could be created. Another is the Netscape "Create URL object" option (or Netscape drag and drop pages). This program works under OS/2 and Windows (tested on NT). Syntax PPWCURL[.CMD] Command [CommandsParameters] [Options] The program takes a number of commands as follows: 1. VERSION? The program will return (not displayed) its version number. 2. SOCKETVERSION? The program will return (not displayed) the version of "RxSock.DLL" in use (for "http" checks). 3. FTPVERSION? The program will return (not displayed) the version of "RxFtp.DLL" in use (for "ftp" checks). 4. SOCKETREADY? The program will return (not displayed) "OK" if "http" checking is possible or a reason why not. 5. FTPREADY? The program will return (not displayed) "OK" if "ftp" checking is possible or a reason why not. 6. CHECK1URL OneUrl The program will return (not displayed) "OK" if the URL (with begins with "http://" or "ftp://" can be accessed or a reason why it couldn't. 7. CHECKLISTEDURLS [+]UrlFileMask1 ... The program will read the file or files specified and sort the URLs listed. If the file mask is preceeded by "+" then all subdirectories below the one specified are also processed. This option also allows OS/2 WPS URL objects to be tested, just open up the properties to determine the path. Within each file blank lines and lines that begin with ';' are ignored as is leading and trailing whitespace on all lines and URL duplicates. The progress of URL checking is displayed on screen and the return code is the total number of failing URL's. It is highly recommended that you use the "/CheckDays" switch even if you give it a value of 1 (recheck every day). 8. CHECKURLSINHTML [+]HtmlFileMask1 ... The program will read the file or files specified. The files are scanned for URLs, otherwise it functions pretty much like the "CHECKLISTEDURLS" command. PPWCURL Options 1. /MemoryFile[:NameOfFile] A memory file is used to hold details about checked URLs. It becomes really useful if the "/CheckDays" option is also used as this program will then not retest all URLs but can be more selective (for example not retest URLs you only checked yesterday). 2. /CheckDays[:OkUrlMinAge[-OkUrlMaxAge]] This will determine how long ago is too long since the last successful URL check. For example setting this to 14-14 means that a URL which tested OK today will not be retested for 2 weeks. You must have used the "/MemoryFile" switch to specify a file. If you had have said "14-21" then for each URL a random day between 14 and 21 would be chosen. This allows the URL checking to gradually spread, that is every two weeks you are not doing the full check. Note that once a URL has failed this checking is bypassed, the next time you run this program will will always retest URLs that failed on the previous run. 3. /ForgetDays[:NumberOfDays] By default old URLs are dropped from memory if not referred to for a significant period of time. This option can be used to specify how old a URL can become or to turn off the dropping (don't specify a value). 4. /ReadTimeOut[:NumberOfSeconds] Allows you to specify the maximum number of seconds we will wait for a server to respond to a request. A blank value will restore default. 5. /TimeOutRetry[:NumberOfSeconds] If a URL check fails with a timeout, you may specify that after URL checking has completed that these URLs be retried. If a value of 0 is supplied you don't wish a retry otherwise the value represents the timeout value in seconds that should be used. A blank value will restore default. It may be wise to increase the value past that used on the "/ReadTimeOut" switch. 6. /GetEnv:NameOfEnvVar Allows you to pick up options from an environment variable. 7. /ErrorFile[:[+]NameOfFile] Create new or append to old error file. This file will hold the complete list of failing URLs along with the reason for the failure in a format that this program can accept as input (rename file first!). This is probably less useful if "/IniCheckDays" is specified. 8. /FtpEmail:YourEmailAddress When checking FTP addresses this value is used for the password to the "Anonymous" user, if not supplied a default (obviously incorrect) value is used. 9. /TestUrl[:Url] I don't know of any way I can tell if the network is available. By default a known internet URL is checked as this is expected to exist, if found you must have access to the internet. You can either change URLs (if testing intranet URLs etc) or turn it off altogether. 10. /MemoryBackupLevel[:Level] This determines how many memory file backups are kept. A value of 0 turns off backups otherwise a value of 1 to 9 is required. 11. /AskIfMoveOk[:YES|NO] When URLs are moved you may or may not wish to update your address. Some sites stupidly force moves which they believe will never be seen by a user (although what these sites are doing does slow the browser slightly). Rather than treat each move as an error you can be asked for your opinion (after all other checking has taken place). PPWCURL Environment Variables 1. PPWCURL_DEBUG=[+]NameOfFile Create new or append to old debug file. This file will hold much more detail about the programs internal workings. This will slow down URL checking. If reporting problems with this command please send me the debug output. 2. PPWCURL_OPTIONS=Options This allows you to specify command line options in the environment. When a filename is required it may contain the text "{Date}" or "{Time}", these get replaced with "yyyymmdd" or "hhmmss". EXAMPLE This batch file reads in 40 or so ".URL" files (created when I built my web pages - see "VALRURL.H") as well as the list of WPS URLs that I have collected in multiple folders: @echo off setlocal REM *** WANT a DEBUG FILE (19990820.DBG etc) ******************************** set ppwcurl_debug=out\remote.url\{Date}.DBG REM *** INIT COMMAND LINE OPTIONS ******************************************* SET CLOPTIONS= REM *** WANT a ERROR FILE (19990820.ERR etc) ******************************** SET CLOPTIONS=%CLOPTIONS% /ErrorFile:out\remote.url\{Date}.ERR REM *** SET UP SOME LONG TERM MEMORY **************************************** SET CLOPTIONS=%CLOPTIONS% /MemoryFile:out\remote.url\CheckUrl.MEM REM *** Check only if last checked 20-30 days ago (spreads out checking) **** SET CLOPTIONS=%CLOPTIONS% /CheckDays:20-30 REM Drop URLs we haven't looked at for more than 100 days ******************* SET CLOPTIONS=%CLOPTIONS% /ForgetDays:100 REM *** Don't wait more than 15 seconds for a response from server ********** SET CLOPTIONS=%CLOPTIONS% /ReadTimeout:15 REM *** Test all WPS URLs (in "E:\DB\URLS" and subfolders) created by **** REM *** Netscape ("Create URL object" or with GUI gizmo near "bookmarks")**** REM *** Also "*.URL" files (All URLs used in my web pages - VALRURL.H) **** ppwcurl.cmd CheckListedUrls +E:\DB\URLS\*.* out\remote.url\*.URL %CLOPTIONS% REM *** Test URLs in HTML pages ********************************************* REM ppwcurl.cmd CheckUrlsInHtml out\*.htm %CLOPTIONS% Note that the batch file does not retest a previously successfully tested URL for 20-30 days, this means that usually I'm only testing new or previously failed URLs, plus a small number of older URLs. ═══ 9.5. PPWSORT.H - Sorting ═══ PPWSORT.H - Sorting PPWIZARD has an internal sort routine called SortArray(), where possible it is recommended that it be used however the header file has the following advantages: 1. You can generate sort code inline when generating Rexx code (PPWIZARD's internal code will not be available when the generated code executes!). 2. You can sort more than one array at a time, this allows you to keep associated information together. 3. The compare operation can be as complex as you wish. 4. If you wish to sort an array with a known name (probably usual thing in PPWIZARD code) and there are many entries in the array then the sort can be much faster. There are two generic macros you can choose from, "SortArray" generates a PPWIZARD #evaluate command to perform the sort and "GenRexx2Sort" which generates the rexx code. The first element in the array(s) is element 1 (not 0). The Generic Macro Parameters 1. COUNT This is used to supply the number of elements that you are sorting. 2. PREFIX By default the all variables used in the generated sort code are prefixed by "Srt" this parameter gives you the chance to remove any conflicts you may have (you may already have your own variables that begin with "Srt"). 3. GREATER You need to supply the rexx code which sets the "SrtGreater" variable to "1" if the first element is greater than the second or '0' otherwise. If the name of the array can't be hard coded (its name is held in a variable), the rexx value() routine will need to be used for all variable accesses. 4. SWAP You need to supply the rexx code which swaps elements. The last two macro parameters will need to use the "SrtIndex1" and "SrtIndex2" variables (using default prefix!) which hold the indexes of the elements to be compared or swapped. Some Non-Generic macros While the generic macros above are very powerful (you can do anything after all) most people will probably never use them and use the macros described below (some of the same generic macro parameters are supported). There are 2 macros which you can use to sort either 1 or 2 arrays (whose names are known - fixed). The default is that the ".0" element holds the number of items in the array and the sort is ascending. The macros are "GenRexx2Sort1Array" and "GenRexx2Sort2Arrays". With the 2 array sort macro the first array is sorted and the 2nd array is assumed to hold associated data. There is one macros which you can use to sort a single array whose name is only known at runtime (not fixed), its name is "GenRexx2Sort1ArrayIndirect". EXAMPLES This example shows the named array "Fred" being sorted: <$GenRexx2Sort1Array ARRAY="Fred">; This time we want the first 4 items sorted in decending order: <$GenRexx2Sort1Array ARRAY="Fred" Compare="<" Count="4">; We want a "SortArray" routine in our generated rexx code: ... call SortArray "fred"; return; ... ... /*==========*/ SortArray: /*==========*/ ArrayNamedIn = translate(arg(1)); ;;Holds name of array <$GenRexx2Sort1ArrayIndirect NamedIn="ArrayNamedIn">; return; PPWSORT.H ;---------------------------------------------------------------------------- ; MODULE NAME: PPWSORT.H ; ; $Author: Dennis_Bareis $ ; $Revision: 1.2 $ ; $Date: 02 Oct 1999 18:40:58 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/PPWSORT.H_V $ ; ; DESCRIPTION: PPWIZARD has a "SortArray()" routine which can be used ; to sort a single array. It does have some flexability ; in how it compares entries. ; ; This header file would be used to handle sort ; requirements that are not possible using "SortArray()". ; ; This header allows you to: ; ; * Imbed the sort routine between PPWIZARD commands. ; ; * Imbed the sort routine between rexx commands. ; ; * Sort more than one array at a time, for example ; you may have multiple arrays storing associated ; information that should all be sorted together. ; ; * Do any sort of compare, no matter how complex. ; ; ; EXAMPLE1 - Inline Rexx code (use "SortArray" for inline ; PPWIZARD code). Array 'A' is being sorted. ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ArrayName = arg(1); ;;Caller passed "A" ; <$GenRexx2Sort \ ; COUNT=^_valueG(ArrayName || '.0')^ \ ; GREATER=^SrtGreater = _valueG(ArrayName || '.SrtIndex1') >> _valueG(ArrayName || '.SrtIndex2')^ \ ; SWAP=^SrtTemp = _valueG(ArrayName || '.SrtIndex1'); -\ ; call _valueS ArrayName || '.SrtIndex1', _valueG(ArrayName || '.SrtIndex2'); -\ ; call _valueS ArrayName || '.SrtIndex2', SrtTemp -\ ; ^ -\ ; > ; ; Note ">>" being used in the compare, if the data being ; sorted is numeric use '>' instead (or else)!!!!!! ; ; EXAMPLE2 - Exactly same as Example 1 ; hardcoded - can't handle other arrays). ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ArrayName = translate(arg(1)); ;;Caller passed "A" (handle possible value() bug!) ; <$GenRexx2Sort1ArrayIndirect NamedIn="ArrayName"> ; ; EXAMPLE3 - In this case the name of the array ("A" is ; hardcoded - can't handle other arrays). ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; <$GenRexx2Sort1Array ARRAY="A"> ; ;---------------------------------------------------------------------------- ;--- Only include once ------------------------------------------------------ #ifndef VERSION_PPWSORT_H ;--- Define the version number of this header file -------------------------- #define VERSION_PPWSORT_H 99.269 #require 99.269 ;--- For use within PPWIZARD for immediate sorting of array (PPWIZARD Command!) --- #define SortArray \ #evaluate '' ^<$GenRexx2Sort COUNT={$COUNT} GREATER={$GREATER} SWAP={$SWAP}>^ ;--- Generates the rexx code to perform sorting (sort one "NAMED" array) ---- #define GenRexx2Sort1Array \ <$GenRexx2Sort \ COUNT=^{$Count="{$Array}.0"}^ \ PREFIX=^{$Prefix="Srt"}^ \ GREATER=^SrtGreater = {$Array}.SrtIndex1 {$Compare=">"} {$Array}.SrtIndex2^ \ SWAP=^SrtTemp = {$Array}.SrtIndex1; -\ {$Array}.SrtIndex1 = {$Array}.SrtIndex2; -\ {$Array}.SrtIndex2 = SrtTemp -\ ^ -\ > ;--- Generates the rexx code to perform sorting (sort 2 "NAMED" arrays) ----- #define GenRexx2Sort2Arrays \ <$GenRexx2Sort \ COUNT=^{$Count="{$Array1}.0"}^ \ PREFIX=^{$Prefix="Srt"}^ \ GREATER=^{$Prefix}Greater = {$Array1}.{$Prefix}Index1 {$Compare=">"} {$Array1}.{$Prefix}Index2^ \ SWAP=^{$Prefix}Temp = {$Array1}.{$Prefix}Index1; -\ {$Array1}.{$Prefix}Index1 = {$Array1}.{$Prefix}Index2; -\ {$Array1}.{$Prefix}Index2 = {$Prefix}Temp; -\ {$Prefix}Temp = {$Array2}.{$Prefix}Index1; -\ {$Array2}.{$Prefix}Index1 = {$Array2}.{$Prefix}Index2; -\ {$Array2}.{$Prefix}Index2 = {$Prefix}Temp -\ ^ -\ > ;--- Generates the rexx code to perform sorting (array name not hard coded) - #define GenRexx2Sort1ArrayIndirect \ <$GenRexx2Sort \ COUNT=^{$Count="_valueG({$NamedIn} || '.0')"}^ \ PREFIX=^{$Prefix="SRT"}^ \ GREATER=^{$Prefix}Greater = _valueG({$NamedIn} || '.{$Prefix}INDEX1') {$Compare=">"} _valueG({$NamedIn} || '.{$Prefix}INDEX2')^ \ SWAP=^{$Prefix}Temp = _valueG({$NamedIn} || '.{$Prefix}INDEX1'); -\ call _valueS {$NamedIn} || '.{$Prefix}INDEX1', _valueG({$NamedIn} || '.{$Prefix}INDEX2'); -\ call _valueS {$NamedIn} || '.{$Prefix}INDEX2', {$Prefix}Temp -\ ^ -\ > ;--- Generates the rexx code to perform sorting (GENERIC) ------------------- #DefineRexx GenRexx2Sort {$Prefix="SRT"}M = 1 {$Prefix}Count = {$COUNT}; do while (9 * {$Prefix}M + 4) < {$Prefix}Count {$Prefix}M = {$Prefix}M * 3 + 1 end /* do while */ do while {$Prefix}M > 0 {$Prefix}K = {$Prefix}Count - {$Prefix}M do {$Prefix}J = 1 to {$Prefix}K {$Prefix}Index1 = {$Prefix}J do while {$Prefix}Index1 > 0 ;--- Work out what to compare it with ---------------- {$Prefix}Index2 = {$Prefix}Index1 + {$Prefix}M; ;--- User user supplied logic to check for greater --- {$Greater}; ;--- Swap if required -------------------------------- if {$Prefix}Greater then do {$Swap}; end; else leave; ;--- Prepare for the next loop ----------------------- {$Prefix}Index1 = {$Prefix}Index1 - {$Prefix}M end /* do while {$Prefix}Index1 > 0 */ end /* do {$Prefix}J = 1 to {$Prefix}K */ {$Prefix}M = {$Prefix}M % 3 end /* while {$Prefix}M > 0 */ #DefineRexx #ifdef CommentBlock /* (Saturday 07/08/1999, 20:32:20, by Dennis_Bareis) */ **+-------------------------------------------------------------------------- **|;--- Generates the rexx code to perform sorting (GENERIC) ------------------- **|#DefineRexx GenRexx2Sort **| {$Prefix="Srt"}Count = {$COUNT}; **| {$Prefix}Distance = {$Prefix}Count % 2; **| do while {$Prefix}Distance > 0 **| do until {$Prefix}Finished; /* start of mini-bubblesort loop */ **| {$Prefix}Finished = 1; **| do {$Prefix}Index1 = 1 to {$Prefix}Count - {$Prefix}Distance **| ;--- We now compare and swap items {$Prefix}Index1 and {$Prefix}Index1+{$Prefix}Distance --- **| {$Prefix}Index2 = {$Prefix}Index1 + {$Prefix}Distance; **| **| ;--- User user supplied logic to check for greater --- **| {$GREATER}; **| **| ;--- Swap if required -------------------------------- **| if {$Prefix}Greater then **| do **| ;--- User user supplied logic to swap items ------ **| {$Swap}; **| {$Prefix}Finished = 0; **| end; **| end; **| end; /* end of mini-bubblesort loop */ **| {$Prefix}Distance = {$Prefix}Distance % 2; **| end; **|#DefineRexx **+-------------------------------------------------------------------------- #endif /* (Saturday 07/08/1999, 20:32:20, by Dennis_Bareis) */ #endif ═══ 9.6. OL_DOC.DH - Document Creation ═══ OL_DOC.DH - Document Creation The header file "OL_DOC.DH" provides a powerful range of facilities to allow you to create electronic documentation. It currently supports IPF/INF and HTML generation but there is no reason this can't be extended in the future. The IPF and HTML versions of the document you are now viewing were produced by the same method. Note that the facilities provided here much simplify the generation of complex documentation and I would recommend it's use even if you were limiting yourself to a single target output format. Using the facilities of this header file your source files need contain no IPF or HTML tags, although it is simple to conditionally include your own HTML or IPF tags as required. The examples batch files (below) will give you an idea of how to invoke ppwizard to generate documentation however please note that it is very important not to hardcode a filename on the /output switch when generating html or ppwizard will fail as each heading will try to update the same file. This is not a recommended way to produce HTML webpages. It's aim is to provide a subset of commands that are useful in the creation of documentation (which may of course be placed on the web). For more information have a look at the tags and options documentation as well as the simplistic example source. CREATING HTML OUTPUT This shows a simple batch file which takes a source file and generates one or more HTML pages: @echo off REM *** Name of the .INF **************************************************** setlocal if "%1" == "" SET INFNAME=TEST if not "%1" == "" SET INFNAME=%1 REM *** Generate the .HTM *************************************************** set DEBUG=/debug set DEBUG= call ppwizard.cmd %INFNAME%.D %DEBUG% /output:out\*.htm /crlf /define:DocType=HTML Note that the /output switch above specified "out\*.htm", all pages will therefore be generated in the "out" directory and they will all have the extension ".htm". Note that the "*" is very important, you must not "hardcode" the name of the html file since for html generation each Heading generates a new page and with a hardcoded name each pages will use the same filename (and ppwizard will then fail)! CREATING IPF OUTPUT This shows a simple batch file which takes a source file and generates the IPF source which can then be compiled to generate an OS/2 INF file: @echo off REM *** Name of the .INF **************************************************** setlocal if "%1" == "" SET INFNAME=TEST if not "%1" == "" SET INFNAME=%1 REM *** Generate the .IPF *************************************************** set DEBUG= set DEBUG=/debug call ppwizard.cmd %INFNAME%.D %DEBUG% /output:out\*.ipf /crlf /define:DocType=IPF if errorlevel 1 goto ERROR REM *** Compile the .IPF to create a .INF *********************************** SETLOCAL CD OUT IPFC.EXE %INFNAME%.IPF /S /INF if errorlevel 1 goto ERROR goto EndBatch :ERROR echo ERROR: Somethings wrong! :EndBatch ═══ 9.6.1. Tags ═══ Tags This section describes the tags that are available when you make use of the "OL_DOC.DH" header file. The document you are now viewing was produced using the tags documented here. There are some options which can be used to alter how the tags function. The following tags are heading and Heading and hypertext link related:  <$Heading>  <$HeadingAt>  <$HeadingDown>  <$HeadingRestore>  <$HeadingSave>  <$HeadingUp>  <$LinkTo>  <$Target> The following tags are used to positioning text within your document:  <$BR>  <$P> The following tags are used to format character text within your document:  <$Bold>  <$BoldItalic>  <$BoldUnderline>  <$DarkGreen>  <$Italic>  <$Magenta>  <$Red> The following tags are used to handle different types of lists:  <$OrdList>  <$SimpleList>  <$UnNumberedList>  <$UnNumberedListCompact>  <$SimpleListCompact>  <$OrdListCompact>  <$Li> The following tags are used to include examples:  <$ExampleFile>  <$Example>  <$ExampleFormatted> The following tags are used to handle some problem characters:  <$Colon>  <$Amp>  <$NoBreakingBlank> The following tags are used to generate an index for your document:  <$Index1>  <$Index2> The following tags do not fit into any of the above categories:  <$DocumentStart>  <$DocumentEnd>  <$Title> ═══ 9.6.1.1. Headings and Links ═══ Headings and Links The following tags are heading and Heading and hypertext link related:  <$Heading>  <$HeadingAt>  <$HeadingDown>  <$HeadingRestore>  <$HeadingSave>  <$HeadingUp>  <$LinkTo>  <$Target> ═══ 9.6.1.1.1. <$Heading> ═══ <$Heading> This "OL_DOC.DH" tag allows you to specify a new section of your document at the current heading level. In a HTML document this will cause a new HTML page (file) to be created. The heading also marks a destination for a hypertext link. The following tags can be used to adjust the heading level:  <$HeadingAt>  <$HeadingUp>  <$HeadingDown>  <$HeadingRestore>  <$HeadingSave> If you wish to allow hypertext linking to a section of documentation within this heading (its not big enough for its own page) then you can use the <$Target> tag. SYNTAX <$Heading TEXT="?" [ID="?"]>> The parameters for this tag are:  TEXT This describes the text that should be used to describe this section of the document.  ID This is an optional parameter. If not supplied the "TEXT" parameter also becomes the ID. The "ID" is an alias that is used in any references to this section (such as on a "<$LinkTo>" tag). In most cases you probably won't specify this parameter. The case of this parameter is ignored. ═══ 9.6.1.1.2. <$HeadingAt> ═══ <$HeadingAt> This "OL_DOC.DH" tag allows you to specify exactly at what "level" the next heading will be placed, valid values are 1 (top) to 6 (bottom). This is handy if you wish to enforce a particular level and not worry about using HeadingUp tags to restore the correct level. This is (or should be) a rarely used tag, even when required a better way would normally be to use HeadingSave and HeadingRestore. SYNTAX <$HeadingAt LEVEL="?"> The parameters for this tag are:  LEVEL This should be a value between 1 and 6. ═══ 9.6.1.1.3. <$HeadingDown> ═══ <$HeadingDown> This "OL_DOC.DH" tag allows you to increase the current heading level by one. An error will be generated if you attempt to generate a Heading at or above level 7! SYNTAX <$HeadingDown> There are no parameters for this tag. ═══ 9.6.1.1.4. <$HeadingRestore> ═══ <$HeadingRestore> This "OL_DOC.DH" tag allows you to restore the heading level to a value that you previously saved. The advantage of this tag over the HeadingAt tag is that you don't need to know or care what the level is. SYNTAX <$HeadingRestore NAME="?"> The parameters for this tag are:  NAME This should be the name that you used on the HeadingSave tag. ═══ 9.6.1.1.5. <$HeadingSave> ═══ <$HeadingSave> This "OL_DOC.DH" tag allows you to "name" the current heading level. This allows you to restore it at some future location. SYNTAX <$HeadingSave NAME="?"> The parameters for this tag are:  NAME This is the name that you wish to give the current heading level! ═══ 9.6.1.1.6. <$HeadingUp> ═══ <$HeadingUp> This "OL_DOC.DH" tag allows you to decrease the current heading level by one. An error will be generated if you attempt to generate a Heading at or below level 0! SYNTAX <$HeadingUp> There are no parameters for this tag. ═══ 9.6.1.1.7. <$LinkTo> ═══ <$LinkTo> This "OL_DOC.DH" tag allows you to create a hypertext link to another part of your document. Targets of the link can be specified with the following tags:  <$Heading>  <$Target> Note that this tag can refer to target locations which are not yet defined. This also means that the targets are not validated. SYNTAX <$LinkTo TEXT="?" [ID="?"]> [TARGET="?"]>> The parameters for this tag are:  TEXT This is the text that the user will click on to jump to the target location in your document.  ID This is an optional parameter. If not supplied the "TEXT" parameter also becomes the ID. The "ID" is an alias that is used in any references to this section (such as on a "<$LinkTo>" tag). In most cases you probably won't specify this parameter. The case of this parameter is ignored.  TARGET You use this optional parameter to refer to a target you name with the <$Target> tag. This parameter is ignored when generating IPF documents. ═══ 9.6.1.1.8. <$Target> ═══ <$Target> This "OL_DOC.DH" tag allows you to specify a destination for a hypertext link. In most cases you should organise your document so that each important component is in its own page (using the <$Heading> tag) however there will be times when the information is so small as to not need its own page. Note that this tag has no effect in IPF documents. The <$LinkTo> tag can be used to create a hypertext link to this heading. SYNTAX <$Heading NAME="?"> The parameters for this tag are:  NAME This names the destination. To link to this named part of your document you will need to use the "TARGET" parameter on the <$LinkTo> tag. ═══ 9.6.1.2. Text Positioning ═══ Text Positioning The following tags are used to positioning text within your document:  <$BR>  <$P> ═══ 9.6.1.2.1. <$BR> ═══ <$BR> This "OL_DOC.DH" tag is used to position text. The following text will appear on a new line. This tag must appear on a line of its own. SYNTAX <$BR> EXAMPLE <$p>The parameters for this tag are<$colon> <$UnNumberedList> <$li><$Bold Text="TEXT"> <$Br> This text is made bold. <$eUnNumberedList> ═══ 9.6.1.2.2. <$P> ═══ <$P> This "OL_DOC.DH" tag is used to position text. The following text will appear in a new paragraph. SYNTAX <$P> EXAMPLE <$p>This is paragraph 1. <$p>This is paragraph 2. ═══ 9.6.1.3. Character Formatting ═══ Character Formatting The following tags are used to format character text within your document:  <$Bold>  <$BoldItalic>  <$BoldUnderline>  <$DarkGreen>  <$Italic>  <$Magenta>  <$Red> EXAMPLE - Source This example does some simple formatting: <$p>This paragraph contains <$Bold Text="some bold"> text! <$p><$DarkGreen Text=^This is a \ multi line (in source code at least) \ paragraph which is completely green. -\ ^> EXAMPLE - Generated Output This paragraph contains some bold text! This is a multi line (in source code at least) paragraph which is completely green. ═══ 9.6.1.3.1. <$Bold> ═══ <$Bold> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$Bold TEXT="?"> EXAMPLE <$Bold TEXT="Some Text">. ═══ 9.6.1.3.2. <$BoldItalic> ═══ <$BoldItalic> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$BoldItalic TEXT="?"> EXAMPLE <$BoldItalic TEXT="Some Text">. ═══ 9.6.1.3.3. <$BoldUnderline> ═══ <$BoldUnderline> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$BoldUnderline TEXT="?"> EXAMPLE <$BoldUnderline TEXT="Some Text">. ═══ 9.6.1.3.4. <$DarkGreen> ═══ <$DarkGreen> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$DarkGreen TEXT="?"> EXAMPLE <$DarkGreen TEXT="Some Text">. ═══ 9.6.1.3.5. <$Italic> ═══ <$Italic> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$Italic TEXT="?"> EXAMPLE <$Italic TEXT="Some Text">. ═══ 9.6.1.3.6. <$Magenta> ═══ <$Magenta> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$Magenta TEXT="?"> EXAMPLE <$Magenta TEXT="Some Text">. ═══ 9.6.1.3.7. <$Red> ═══ <$Red> This "OL_DOC.DH" tag is used to adjust the character formatting of some text. The text will appear like this. SYNTAX <$Red TEXT="?"> EXAMPLE <$Red TEXT="Some Text">. ═══ 9.6.1.4. Lists ═══ Lists The following tags are used to handle different types of lists:  <$OrdList>  <$SimpleList>  <$UnNumberedList>  <$UnNumberedListCompact>  <$SimpleListCompact>  <$OrdListCompact>  <$Li> EXAMPLE - Source This example does some simple formatting: <$p>Things to do<$Colon> <$OrdListCompact> <$li>Make Perfect. <$li>Make sure all bugs removed. <$li>Finish doco. <$li>I'll never get here! <$eOrdListCompact> <$p>The parameters are<$Colon> <$UnNumberedList> <$li><$Bold Text="TEXT"> <$br> This is the text that the user will click on. <$li><$Bold Text="TARGET"> <$br> You use this optional parameter to refer to a target. <$eUnNumberedList> EXAMPLE - Generated Output Things to do: 1. Make Perfect. 2. Make sure all bugs removed. 3. Finish doco. 4. I'll never get here! The parameters are:  TEXT This is the text that the user will click on.  TARGET You use this optional parameter to refer to a target. ═══ 9.6.1.4.1. <$LI> - List Item ═══ <$LI> - List Item This "OL_DOC.DH" tag is used to specify a new list item. Lists are declared using one of the following tags:  <$OrdList>  <$UnNumberedList>  <$UnNumberedListCompact>  <$OrdListCompact> SYNTAX <$LI> There are no parameters for this tag. For an example have a look at the Lists documentation. ═══ 9.6.1.4.2. <$OrdList> - Numbered List ═══ <$OrdList> - Numbered List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eOrdList>" tag is encountered. Lists can be nested. Each list item begins with "<$li>". List items are separated by a blank line, if this is not desired then use the "<$OrdListCompact>" tags instead. SYNTAX <$OrdList> <$li>Item1 <$li>Item2 <$eOrdList> For an example have a look at the Lists documentation. ═══ 9.6.1.4.3. <$OrdListCompact> - Numbered List ═══ <$OrdListCompact> - Numbered List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eOrdListCompact>" tag is encountered. Lists can be nested. Each list item begins with <$li>. List items are not separated by a blank line, if you want one then use the "<$OrdList>" tags instead. SYNTAX <$OrdListCompact> <$li>Item1 <$li>Item2 <$eOrdListCompact> For an example have a look at the Lists documentation. ═══ 9.6.1.4.4. <$SimpleList> - Numbered List ═══ <$SimpleList> - Numbered List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eSimpleList>" tag is encountered. Lists can be nested. Each list item begins with "<$li>". List items are separated by a blank line, if this is not desired then use the "<$SimpleListCompact>" tags instead. SYNTAX <$SimpleList> <$li>Item1 <$li>Item2 <$eSimpleList> For an example have a look at the Lists documentation. ═══ 9.6.1.4.5. <$SimpleListCompact> - Numbered List ═══ <$SimpleListCompact> - Numbered List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eSimpleListCompact>" tag is encountered. Lists can be nested. Each list item begins with <$li>. List items are not separated by a blank line, if you want one then use the "<$SimpleList>" tags instead. SYNTAX <$SimpleListCompact> <$li>Item1 <$li>Item2 <$eSimpleListCompact> For an example have a look at the Lists documentation. ═══ 9.6.1.4.6. <$UnNumberedList> - Dotted List ═══ <$UnNumberedList> - Dotted List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eUnNumberedList>" tag is encountered. Lists can be nested. Each list item begins with <$li>. List items are separated by a blank line, if this is not desired then use the "<$UnNumberedListCompact>" tags instead. SYNTAX <$UnNumberedList> <$li>Item1 <$li>Item2 <$eUnNumberedList> For an example have a look at the Lists documentation. ═══ 9.6.1.4.7. <$UnNumberedListCompact> - Dotted List ═══ <$UnNumberedListCompact> - Dotted List This "OL_DOC.DH" tag is used to define the start of an ordered list. The list ends when the "<$eUnNumberedListCompact>" tag is encountered. Lists can be nested. Each list item begins with <$li>. List items are not separated by a blank line, if you want one then use the "<$UnNumberedList>" tags instead. SYNTAX <$UnNumberedListCompact> <$li>Item1 <$li>Item2 <$eUnNumberedListCompact> For an example have a look at the Lists documentation. ═══ 9.6.1.5. Include Examples ═══ Include Examples The following tags are used to include examples:  <$ExampleFile>  <$Example>  <$ExampleFormatted> OPTIONS Here are some of the options that you can use to modify the look and feel of examples:  PRE_COLOR_HTML  PRE_COLOR_IPF  PRE_STYLE_OTHER_HTML EXAMPLE - Source This shows some example text being included from a file (only part of the file is used): <$ExampleFile INDENT=0 FILE="OlDocXmp.DH" FRAGMENT="[CharacterFormatting]" STATE="REMEMBER"> <$ExampleFile INDENT=8 FILE="OlDocXmp.DH" FRAGMENT="[CharacterFormatting]"> EXAMPLE - Generated Output <$p>This paragraph contains <$Bold Text="some bold"> text! <$p><$DarkGreen Text=^This is a \ multi line (in source code at least) \ paragraph which is completely green. -\ ^> Notice the hypertext links that were placed into the displayed source code in the above example code does not show the preparation required. This is demonstrated in the <$ExampleFile> example. Also note that unsafe (in example) characters such as "<" and others are tagged in such a way that they will correctly display. The second lot of output is below, notice no hypertext links and the greater indenting (I could have changed font and color as well if I'd wished): <$p>This paragraph contains <$Bold Text="some bold"> text! <$p><$DarkGreen Text=^This is a \ multi line (in source code at least) \ paragraph which is completely green. -\ ^> ═══ 9.6.1.5.1. <$ExampleFile> ═══ <$ExampleFile> This "OL_DOC.DH" tag allows you to include all or part of a file in such a manner that it appears to be viewer (IPF or HTML) much like you'd see it in a text editor. The point of this tag is to be able to include example code as is without any modifications being manually applied. SYNTAX <$ExampleFile FILE="?" [STATE="?"]> [INDENT="?"]> [FRAGMENT="?"]> [ASIS="?"]> The parameters for this tag are:  FILE This is the name of the text file that includes the example. This can be unmodified code.  FRAGMENT If you don't want to include the whole file then you must mark the start and end lines with a unique string. Only the part between these lines will be included. This allows you to set up a larger file containing all your examples in one place if that is your wish.  INDENT Normally everything is indented a small amount. You may wish to remove the indent or even make it bigger. The value you supply is the number of leading spaces you require.  SPELL Normally spell checking is not allowed to occur in examples. You can specify "ON" if you wish to allow it or "OFF" if not. Note that this does not turn on spell checking it just indicates if spell checking is allowed.  ASIS All "normal" characters are already taken care of such that they will correctly display in a browser, for example when generating html "<" is converted to "<". If you find other characters you'd also like automatically taken care of you can define these (international characters might need more work). Have a look at the #AsIs command, it shows you how to set up the modifications. This parameter can take one or more space separated previously setup ASIS state names.  STATE The contents of this parameter are used in a "#AutoTagState +" command. If you don't want the automatic tagging you previously set up to occur then don't pass this parameter. You would normally pass "REMEMBER" to have them occur. EXAMPLE - Source This example shows some HTML source code. ;--- Create a new clear state, set up new ASIS state, restore state --- #AutoTagState + ;--- Set up aliases for all dangerous character so that they display OK in browser --- #if ['<$DocType>' = 'HTML'] ;--- HTML being generated --- #RexxVar "UMLAUT" =x= "ü" ;;Map an alias (for our use) to the output text #elseif ;--- IPF being generated --- #RexxVar "UMLAUT" =x= "Ъ" ;;This char OK as is in IPF #endif ;--- We defined aliases above only so that we more easily refer to strings, for example an umlaut looks the same in IPF and HTML until alias replaced --- #AutoTag "Ъ" "" ;;Now map char to our alias ;--- Create named ASIS state called "DANGEROUS" --- #AsIs SETUP DANGEROUS #AutoTagState - ;--- Now lets also set up some automatic tagging, adding to existing tagging (only applies to this example otherwise we'd not do it here) --- #AutoTagState + Remember ;;Adding to existing tags (remember current) #AutoTag ^Grn^ ^<$DarkGreen Text='Grn'>^ ;;Because we used aliases we don't need to check if html/ipf etc to do this step ;--- Load the example (a part of the file - fragment) --- <$ExampleFile STATE="REMEMBER" FILE="OLDOCXMP.DH" FRAGMENT="[ExampleFileTag2]" AsIs=^DANGEROUS^> ;--- Already processed example, remove now obsolete tagging --- #AutoTagState - The "ASIS" stuff as well as any common "AUTOTAG" steps would normally only occur once at the start of your document. Note that the tagging that you see above and below to create hypertext links is such common code in my document. EXAMPLE - Generated Output ;--- Some web addresses ----------------------------------------------------- #define HttpMagazineOs2Ezine http://www.os2ezine.com #define HttpOs2SuperSiteMainPage http://www.os2ss.com ;--- Set up some common styles ---------------------------------------------- #define Red {$Text} #define GrЪn {$Text} ;;Note international characters can be used in names #define Bold {$Text} #define Quote “{$Text}” ;;Pretty double quotes ;--- Now for some html stuff ------------------------------------------------

Some <$GrЪn Text="green text"> blah blah... Notice the green text above is what we asked for, all other tagging (hypertext links) occurred because its set up that way at the start of this document. Hopefully you can recognise the power of this facility just from the fact that I can show you the above source and generated output! ═══ 9.6.1.5.2. <$Example> ═══ <$Example> This "OL_DOC.DH" tag allows you to specify the start of an inline example. For large examples it is recommended that the <$ExampleFile> tag be used instead. The example continues until "<$eExample>" is found. SYNTAX <$Example [STATE="?"]> [INDENT="?"]> [ASIS="?"]> ... ... <$eExample> The parameters for this tag are:  STATE The contents of this parameter are used in a "#AutoTagState +" command. If you don't want the automatic tagging you previously set up to occur then don't pass this parameter. You would normally pass "REMEMBER" to have them occur.  INDENT Normally everything is indented a small amount. You may wish to remove the indent or even make it bigger. The value you supply is the number of leading spaces you require.  ASIS All "normal" characters are already taken care of such that they will correctly display in a browser, for example when generating html "<" is converted to "<". If you find other characters you'd also like automatically taken care of you can define these (international characters might need more work). Have a look at the #AsIs command, it shows you how to set up the modifications. This parameter can take one or more space separated previously setup ASIS state names.  SPELL Normally spell checking is not allowed to occur in examples. You can specify "ON" if you wish to allow it or "OFF" if not. Note that this does not turn on spell checking it just indicates if spell checking is allowed. EXAMPLE This is a very simple example, you should have a look at the <$ExampleFile> example for some advanced techniques. <$Example STATE="REMEMBER">

Some sample html. <$eExample> ═══ 9.6.1.5.3. <$ExampleFormatted> ═══ <$ExampleFormatted> This "OL_DOC.DH" tag allows you to specify the start of an inline example. Unlike the <$Example> tag, you have to handle all formatting manually, for this reason it is a rarely used tag. The example continues until "<$eExampleFormatted>" is found. This tag mainly sets up the look and feel of the example, everything else is up to you. SYNTAX <$ExampleFormatted> ... ... <$eExampleFormatted> As you can see there are no parameters for this type of example. EXAMPLE <$ExampleFormatted STATE="REMEMBER"> <P>Some <B>sample html</B>. <$eExampleFormatted> Note that the above tagging is only valid for viewing in a html viewer, the tagging is not valid for IPF. For this reason the following (making use of standard definitions) would be better: <$ExampleFormatted STATE="REMEMBER"> PSome Bsample html/B. <$eExampleFormatted> ═══ 9.6.1.6. Special Characters ═══ Special Characters The following tags are used to handle some problem characters:  <$Colon>  <$Amp>  <$NoBreakingBlank> ═══ 9.6.1.6.1. <$Amp> ═══ <$Amp> This "OL_DOC.DH" tag is used to wherever you want a '&' character. This character is unsafe in IPF documents. EXAMPLE <$p>The parameters 1 <$Amp> 2 are ═══ 9.6.1.6.2. <$Colon> ═══ <$Colon> This "OL_DOC.DH" tag is used to wherever you want a ':' character. This character is unsafe in IPF documents. EXAMPLE <$p>The parameters are<$Colon> ═══ 9.6.1.6.3. <$NoBreakingBlank> ═══ <$NoBreakingBlank> This "OL_DOC.DH" tag is used to wherever you want a space between words however you need both words to be on the same line. ═══ 9.6.1.7. Generate An Index ═══ Generate An Index The following tags are used to generate an index for your document:  <$Index1>  <$Index2> ═══ 9.6.1.7.1. <$Index1> ═══ <$Index1> This "OL_DOC.DH" tag allows you to define top level item for the index. This tag is currently ignored unless generating IPF code. SYNTAX <$Index1 [TEXT="?"]>> The parameters for this tag are:  TEXT This is the text of the index item. If you don't supply this parameter the text supplied on the previous Heading tag is used. EXAMPLE <$Heading Text="Introduction"> <$Index1> ═══ 9.6.1.7.2. <$Index2> ═══ <$Index2> This "OL_DOC.DH" tag allows you to define second level item for the index. This tag is currently ignored unless generating IPF code. SYNTAX <$Index2 [TEXT="?"]>> The parameters for this tag are:  TEXT This is the text of the index item. If you don't supply this parameter the text supplied on the previous Heading tag is used. EXAMPLE <$Heading Text="FAQ"> <$Index2> ═══ 9.6.1.8. Other Tags ═══ Other Tags The following tags do not fit into any of the above categories:  <$DocumentStart>  <$DocumentEnd>  <$Title> ═══ 9.6.1.8.1. <$DocumentStart> ═══ <$DocumentStart> This "OL_DOC.DH" tag defines the start of your document, no other output or tags should be used prior to this tag. SYNTAX <$DocumentStart [TEXT="?"]>> The parameters for this tag are:  TEXT This is the text of the document's title. EXAMPLE <$DocumentStart Text="The PPWIZARD.CMD PREPROCESSOR - "> ═══ 9.6.1.8.2. <$DocumentEnd> ═══ <$DocumentEnd> This "OL_DOC.DH" tag defines the end of your document, no other output or tags should be used after this tag. SYNTAX <$DocumentEnd> There are no parameters for this tag. ═══ 9.6.1.8.3. <$Title> ═══ <$Title> This "OL_DOC.DH" tag allows you to define a title for a section within a page. It is useful as it enforces a common look and feel. SYNTAX <$Title [TEXT="?"]>> The parameters for this tag are:  TEXT This is the text of the title. If you don't supply this parameter the text supplied on the previous Heading tag is used. EXAMPLE <$Title Text="EXAMPLE"> ═══ 9.6.2. Options - "OL_DOC.DH" ═══ Options - "OL_DOC.DH" As with all my header files the intention is to build them in such a way that you never need to modify the header code to get the look and feel that you require. Most of the options get set before the header file gets included. If you would like other things to be user configurable please provide feedback to this effect. There are many options that you can choose which modify the way that tags from OL_DOC.DH function, they are:  DOCTYPE  OL_DOC_HEADINGS_DONT_GENERATE_TITLE  OL_DOC_HTML_8_3_NAMES  OL_DOC_HTML_ALLOW_ROBOTS  OL_DOC_HTML_BODY  OL_DOC_HTML_BOTTOM  OL_DOC_HTML_CONTENTS  OL_DOC_HTML_CONTENTS_TITLE  OL_DOC_HTML_FOOTER  OL_DOC_HTML_GENERATE_SEARCH_ICON  OL_DOC_HTML_GENERATOR_TAGS  OL_DOC_HTML_HOME  OL_DOC_HTML_META_TAGS  OL_DOC_HTML_NEXT  OL_DOC_HTML_NOCONTENTS_HEADER  OL_DOC_HTML_PREV  OL_DOC_HTML_SEARCH  OL_DOC_HTML_TOP  PRE_COLOR_HTML  PRE_COLOR_IPF  PRE_STYLE_OTHER_HTML ═══ 9.6.2.1. DocType ═══ DocType This is a definition which must be set. It indicates the type of output that you required. It may support more types in future (so you should code accordingly as much as possible), currently support are:  HTML  IPF Note that this definition would not normally be used in the source code as this would require you to modify the source to change the output type! You could normally use the "/Define" switch to define the mode. EXAMPLE I recommend as much as possible that you keep your source clear of conditional generation code, a much better way is to keep all conditional stuff in one place and create some macros to hide the differences such as demonstrated here (you may wish to create your own header file which loads "OL_DOC.DH" and sets up the rest of your environment): ;--- Lets create some macros ourselves -------------------------------------- #define RedBold <$Red Text=<$Bold Text=█{$Text}█>> ;;Uses preexisting macros only #if ['<$DocType>' = 'HTML'] ;--- HTML ------------------------------------------------------------ #define MyGreen {$Text} #elseif ;--- IPF ------------------------------------------------------------- #define MyGreen :color fc=darkgreen.{$Text}:color fc=default. #endif EXAMPLE Here I wish to ensure that my code can handle the document type, "OL_DOC.DH" does its own validation however it may have recently introduced a new type that I may need to do something about if I wish to use it. I will not try to (for now) generate anything but HTML or IPF, so lets validate this: ;--- As I user I only support HTML & IPF --- #if '<$DocType>' <> 'HTML' & '<$DocType>' <> 'IPF' #error 'I do not support the document type "<$DocType>"!' #endif ═══ 9.6.2.2. OL_DOC_HEADINGS_DONT_GENERATE_TITLE ═══ OL_DOC_HEADINGS_DONT_GENERATE_TITLE This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default all headings (defined with "<$Heading>") generate a title at the start of each page (using "<$Title>"). Simply define this option (any value) to prevent this from occuring. You would do this if either you don't want any title or you sometimes want the title to differ from the heading. EXAMPLE #define OL_DOC_HEADINGS_DONT_GENERATE_TITLE ;;All my sections already have a title specified #include "OL_DOC.DH" ═══ 9.6.2.3. OL_DOC_HTML_8_3_NAMES ═══ OL_DOC_HTML_8_3_NAMES This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default long html filenames are generated for each html page. You simply define this option (any value) to force "8.3" style filenames to be generated. "8.3" style names would allow them to be browsed under Windows 3.1 and other operating systems without long filename support. EXAMPLE This example shows how to force 8.3 filename generation: #define OL_DOC_HTML_8_3_NAMES #include "OL_DOC.DH" ═══ 9.6.2.4. OL_DOC_HTML_ALLOW_ROBOTS ═══ OL_DOC_HTML_ALLOW_ROBOTS This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default meta tags are placed into the generated HTML to inform robots (such as search engines) not to index the pages. If you do want your pages indexed then simply define this option (any value). EXAMPLE This example shows how to force 8.3 filename generation: #define OL_DOC_HTML_ALLOW_ROBOTS #include "OL_DOC.DH" ═══ 9.6.2.5. OL_DOC_HTML_BODY ═══ OL_DOC_HTML_BODY This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default the body tag of generated html does not have any parameters, you probably wish to alter the background (and link) colors and maybe have a graphic background. To modify the body tag simply provide a full replacement. EXAMPLE This example shows how to specify a white background: #define OL_DOC_HTML_BODY #include "OL_DOC.DH" ═══ 9.6.2.6. OL_DOC_HTML_BOTTOM ═══ OL_DOC_HTML_BOTTOM This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to either remove the button that links you to the bottom of the current page or completely change its look and feel. EXAMPLE #define OL_DOC_HTML_BOTTOM [Bottom] #include "OL_DOC.DH" ═══ 9.6.2.7. OL_DOC_HTML_CONTENTS ═══ OL_DOC_HTML_CONTENTS This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to either remove the button that links you to the contents page or completely change its look and feel. EXAMPLE #define OL_DOC_HTML_CONTENTS [Contents] #include "OL_DOC.DH" ═══ 9.6.2.8. OL_DOC_HTML_CONTENTS_TITLE ═══ OL_DOC_HTML_CONTENTS_TITLE This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default the contents page of the generated html simply says "Contents". This option allows you to supply alternative text. EXAMPLE #define OL_DOC_HTML_CONTENTS_TITLE PPWIZARD CONTENTS #include "OL_DOC.DH" ═══ 9.6.2.9. OL_DOC_HTML_FOOTER ═══ OL_DOC_HTML_FOOTER This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default the generated html does not have a footer, you may wish to have one. The macro you define (if you want a footer) can define the parameter "CONTENTS" which has a value of 'Y' if the footer is for the contents page. EXAMPLE ;--- Define Footer for PPWIZARD manual -------------------------------------- #evaluate DateTime @date('WeekDay') || ' ' || date('Month') || ' ' || substr(date('Sorted'), 7, 2) || ' ' || left(date('Sorted'), 4) || ' at ' || time('Civil')@ #define MadeWithPpwALT My whole website and this manual itself was developed using PPWIZARD (free preprocessor written by Dennis Bareis) #define OL_DOC_HTML_NOCONTENTS_HEADER \ PPWIZARD Manual
#define OL_DOC_HTML_FOOTER \ #if ['{$CONTENTS}' = 'N'] -\
-\ #elseif -\


;;Need line under contents -\ #endif -\
-\ PPWIZARD Manual -\
-\ -\ <$MadeWithPpwALT> -\ -\
-\ <$DateTime> -\
;--- Include Header --- #include "OL_DOC.DH" You might notice that I used the ExampleFile tag to include the real live working copy of the footer from my documentation source. This means that the footer on the bottom of this page exactly matches the code shown above (the sample is not a copy, its the master). ═══ 9.6.2.10. OL_DOC_HTML_GENERATE_SEARCH_ICON ═══ OL_DOC_HTML_GENERATE_SEARCH_ICON This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option allows you to generate a search icon, this is an inbuilt icon which you may want to generate if you also use the OL_DOC_HTML_SEARCH option. EXAMPLE #define OL_DOC_HTML_GENERATE_SEARCH_ICON #define OL_DOC_HTML_SEARCH [Search] #include "OL_DOC.DH" ═══ 9.6.2.11. OL_DOC_HTML_GENERATOR_TAGS ═══ OL_DOC_HTML_GENERATOR_TAGS This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option allows you to either completely remove the generation of the "GENERATOR" meta tag or allow you to replace the existing one with an alternative one of your choice. EXAMPLE - No Generator Tag Wanted #define OL_DOC_HTML_GENERATOR_TAGS #include "OL_DOC.DH" EXAMPLE - Change Tag #define OL_DOC_HTML_GENERATOR_TAGS #include "OL_DOC.DH" ═══ 9.6.2.12. OL_DOC_HTML_HOME ═══ OL_DOC_HTML_HOME This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to specify a button which takes you to a "homepage", by default there is no home button. ═══ 9.6.2.13. OL_DOC_HTML_META_TAGS ═══ OL_DOC_HTML_META_TAGS This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default no other meta tags other than the "OL_DOC_HTML_GENERATOR_TAGS" tag are generated. If you wish to add some then use this definition. EXAMPLE #define OL_DOC_HTML_META_TAGS #include "OL_DOC.DH" ═══ 9.6.2.14. OL_DOC_HTML_NEXT ═══ OL_DOC_HTML_NEXT This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to either remove (unlikely!) the button that links you to the next page or completely change its look and feel. EXAMPLE #define OL_DOC_HTML_NEXT "^}>[Next] #include "OL_DOC.DH" ═══ 9.6.2.15. OL_DOC_HTML_NOCONTENTS_HEADER ═══ OL_DOC_HTML_NOCONTENTS_HEADER This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option allows you to specify text or images etc to appear at the top of all pages except the contents page. Whatever you specify is placed immediately before the images on the top of the page. EXAMPLE #define OL_DOC_HTML_NOCONTENTS_HEADER PPWIZARD Manual
#include "OL_DOC.DH" ═══ 9.6.2.16. OL_DOC_HTML_PREV ═══ OL_DOC_HTML_PREV This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to either remove (unlikely!) the button that links you to the previous page or completely change its look and feel. EXAMPLE #define OL_DOC_HTML_PREV [Prev] #include "OL_DOC.DH" ═══ 9.6.2.17. OL_DOC_HTML_SEARCH ═══ OL_DOC_HTML_SEARCH This is an option which modifies the tags of OL_DOC.DH operate (look and feel). By default there is no search mechanism for the generated HTML, if you can provide one then this option allows you to set up the required icon and any required HTML. EXAMPLE I have a simple javascript search engine that I use to search my pages, I got it to generate "ppwsrch.htm", I wish to create a search button and link to the search page: #define OL_DOC_HTML_SEARCH [Search] #define OL_DOC_HTML_GENERATE_SEARCH_ICON #include "OL_DOC.DH" ═══ 9.6.2.18. OL_DOC_HTML_TOP ═══ OL_DOC_HTML_TOP This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This tag allows you to either remove the button that links you to the top of the current page (from the bottom) or completely change its look and feel. EXAMPLE #define OL_DOC_HTML_TOP [Top] #include "OL_DOC.DH" ═══ 9.6.2.19. PRE_COLOR_HTML ═══ PRE_COLOR_HTML This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option is used to alter the color of the output from the example tags when they generate HTML. You might also wish to modify the PRE_COLOR_IPF option. The color you specify will be ignored by any browser that does not have style sheet support. EXAMPLE #define PRE_COLOR_HTML #FF6600 #include "OL_DOC.DH" ═══ 9.6.2.20. PRE_COLOR_IPF ═══ PRE_COLOR_IPF This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option is used to alter the color of the output from the example tags when they generate IPF. You might also wish to modify the PRE_COLOR_HTML option. EXAMPLE #define PRE_COLOR_IPF darkred #include "OL_DOC.DH" ═══ 9.6.2.21. PRE_STYLE_OTHER_HTML ═══ PRE_STYLE_OTHER_HTML This is an option which modifies the tags of OL_DOC.DH operate (look and feel). This option is used to alter the style of the output from the example tags when they generate HTML. You should not use this option to change the forground color as the PRE_COLOR_HTML option is intended for this purpose. If you use this option the then if you are assigning and styles then they must begin with ';'. The styles you specify will be ignored by any browser that does not have style sheet support. EXAMPLE ;#define PRE_STYLE_OTHER_HTML ;;Leave font as is #define PRE_STYLE_OTHER_HTML ;font-size:80% ;;Make font a little smaller #include "OL_DOC.DH" ═══ 9.6.3. EXAMPLE - TEST.D (source file) ═══ EXAMPLE - TEST.D (source file) ;---------------------------------------------------------------------------- ; MODULE NAME: TEST.D ; ; $Author: Dennis_Bareis $ ; $Revision: 1.4 $ ; $Date: 26 Oct 1999 17:19:28 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/TEST.D_V $ ; ; DESCRIPTION: This example shows the creation of 2 sections. If ; generating HTML (all that currently works!) then 2 files ; will be generated. Currently the "root" output file ; does not get any data, in future it will hopefully be ; a contents page. ; ;---------------------------------------------------------------------------- ;--- As I user I only support HTML & IPF ------------------------------------ #if '<$DocType>' <> 'HTML' & '<$DocType>' <> 'IPF' #error 'The document type "<$DocType>" is unsupported.' #endif ;--- Include document support ----------------------------------------------- ;#define OL_DOC_HTML_8_3_NAMES #define OL_DOC_HTML_BODY #define OL_DOC_HTML_SEARCH [Search] #define OL_DOC_HEADINGS_DONT_GENERATE_TITLE ;;All my sections already have a title specified #include "OL_DOC.DH" ;--- Define the start of the document --------------------------------------- <$DocumentStart Text="Stupid Example Document"> ;--- Lets create some macros ourselves -------------------------------------- #define RedBold <$Red Text=<$Bold Text=█{$Text}█>> ;;Uses preexisting macros only #if ['<$DocType>' = 'HTML'] ;--- HTML ------------------------------------------------------------ #define MyGreen {$Text} #elseif ;--- IPF ------------------------------------------------------------- #define MyGreen :color fc=darkgreen.{$Text}:color fc=default. #endif ;############################################################################ <$Heading Text="Hash Commands"> ;;By default ID = TEXT <$HeadingDown> ;;Sub headings follow ;############################################################################ <$Index1> ;;Same as 'Text="Hash Commands"' <$Title> <$p>An example which stesses things a bit<$Colon> <$Example STATE="REMEMBER"> This is line 1. This is line 2. Note that '&' will get translated as will ';' (you will not notice this in VIEW.EXE of course)! This is line 4. FONT => Some stuff This is line 5. MACRO => <$FRED> This is line 5. SMACRO => <$eExample> <$P>This is an #if ['<$DocType>' = 'IPF'] IPF #elseif HTML (probably) #endif manual. The following commands are valid<$Colon> <$OrdListCompact> <$LI><$LinkTo Text="#def"> <$LI><$LinkTo Text="#inc"> <$eOrdListCompact> <$P>This is the second paragraph, the contents of "c<$Colon>\config.sys" follows<$Colon> <$ExampleFile INDENT=0 FILE="C:\CONFIG.SYS"> <$p>This will load "#def" doco at the "target" <$LinkTo ID="#def" Text="XXXX" Target="XXXX">! ;############################################################################ <$Heading Text="#def"> ;;ID = #def ;############################################################################ <$Index2> <$Title> ;;Title matches heading (no need to specify) <$P>This is a link to <$LinkTo Text="ezine">... <$P>This is a #def. This is a link to <$LinkTo Text="#inc">... <$P>Note that I was using TEXT=ID with "#" included to stress my macros as this character is considered to be invalid and needs to be converted.... <$Target Name="XXXX"> <$p>This is the target "XXXX", you can link to here. <$p>The following shows some different colors used as well as demonstrating an unnumbered list (with space between each entry)<$Colon> <$UnNumberedList> <$LI><$Red Text="This is RED."> <$LI><$Bold Text="This is BOLD."> <$LI><$MyGreen TEXT='This is "MyGreen".'> <$br>This starts on a new line. <$p>This starts a new paragraph. <$LI><$RedBold Text="This is RED <$Amp> BOLD (my custom macro)."> <$eUnNumberedList> <$p>The following shows a compact unnumbered list<$Colon> <$UnNumberedListCompact> <$LI>Item 1 <$LI>Item 2 <$LI>Item 3 <$eUnNumberedListCompact> ;############################################################################ <$Heading ID="#inc" Text="#inc"> ;############################################################################ <$Index2> <$Title> <$P>This is a #inc. This is a link to <$LinkTo Text="#def">... <$P>This is a new paragraph with an example of <$Bold Text="bold"> text. ;############################################################################ <$HeadingUp> <$Heading Text="EXAMPLES"> ;############################################################################ <$Index1> <$Title Text="Example #1 - Not from file"> <$Example STATE="REMEMBER"> This is line 1. This is line 2. Note that '&' will get translated as will ';' (you will not notice this in VIEW.EXE of course)! <$eExample> <$Title Text="Example #1 - NO special Tagging"> <$ExampleFile FILE="C:\AUTOEXEC.BAT"> <$Title Text="Example #2 - Convert 'REM' to '***'"> #AutoTagState + #AutoTag 'REM' '***' <$ExampleFile FILE="C:\AUTOEXEC.BAT" State='REMEMBER'> #AutoTagState - ;--- Define some codes ------------------------------------------------------ #RexxVar "QM" =x= "?" #RexxVar "DOLLAR" =x= "$" #include "EZINE.DH" ;--- End of source code ----------------------------------------------------- <$DocumentEnd> ═══ 9.7. PUSHPOPM.H - Save/Restore Macro Values ═══ PUSHPOPM.H - Save/Restore Macro Values This is a small header file with support for the saving and restoring of macro values. PUSHPOPM.H ;---------------------------------------------------------------------------- ; MODULE NAME: PUSHPOPM.H ; ; $Author: Dennis_Bareis $ ; $Revision: 1.2 $ ; $Date: 13 Nov 1999 13:39:46 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/PUSHPOPM.H_V $ ; ; DESCRIPTION: This is a header file for saving and restoring MACRO ; values. ; ; This is useful where you need to "protect" the value ; from a header file you are including. Fairly rare ; requirement, but handy when you need it. ; ; EXAMPLE: #define XXXX Some value ; <$MacroPush Macro='XXXX'> ;;Save it ; #include "File" ;;Header may change value ; <$MacroPop Macro='XXXX'> ;;Restore it ;---------------------------------------------------------------------------- ;--- Only include once ---------------------------------- #ifndef VERSION_PUSHPOPM_H ;--- Define the version number of this header file --- #define VERSION_PUSHPOPM_H 99.289 ;--- Include nesting validation code ----------------- #include "nestchk.h" <$NestingInit Id="PUSHPOPM" DESC="PUSHPOPM.H stack macro tag"> ;--- Push Macro -------------------------------------- #define MacroPush \ <$NestingInc Id="PUSHPOPM"> -\ #evaluate '' ^MacroPush = MacroGet('{$Macro}')^ -\ #RexxVar 'MacroPush' PUSH ;--- Pop Macro --------------------------------------- #define MacroPop \ <$NestingDec Id="PUSHPOPM"> -\ #RexxVar 'MacroPush' POP -\ #evaluate+ '{$Macro}' 'MacroPush' #endif ═══ 10. Performance ═══ Performance While PPWIZARD is written in rexx a lot of work has gone into keeping it fast. It has a lot of features and I'll probably add more. In general I have added these with no loss of performance (in fact I've generally gained as I've rewritten parts to add new functionality). As PPWIZARD is so powerful you will be tempted to do some very complex things, much like I have in writing the document you are now reading in PPWIZARD macros. This section aims to give you some hints as to what you can do to speed up processing (if you need to). Macro Performance 1. Macro performance is not affected by the number of macros you create. 2. Macro performance is not affected by the length of a definition's name. 3. The #evaluate & #if commands are very slow (on a Pentium 100 you can do about 380/second). If you have large numbers of these in your source then where possible use the #define or #RexxVar command in place of "#evaluate". The #if [] form is very quick and should be used where possible. Better yet for complex logic consider using straight rexx code, possibly defined using #DefineRexx, this allows you to use rexx's "select" etc and rapidly perform complex logic. 4. Keep the macros as short as possible (particularly the line count). 5. Don't include conditional logic where possible. For example if you know at macro definition time that you will never follow a certain path then don't include it (that is conditionally generate the macro once). Not only will the line count decrease but a #if command is one of the slower ones. Another benefit is that its easier to watch whats going on when debug mode is on. 6. In a similar vein to the previous point, if you have to pass a parameter to a macro to conditionally execute a certain path, then it would be better to create multiple variations of the macro and drop the parameter and conditional generation code. 7. To make code easier to understand I usually do one rexx task per #evaluate, however as an evaluate is slow you could bunch a number of rexx commands in one #evaluate command (at least in any of your high use macros). The #DefineRexx command can be used to define a whole series of rexx statements in an easy to read/understand way. 8. You have the choice of storing information in a macro or rexx variable. Look at your main uses for the variable and decide which is best for each situation. If you are doing heaps of rexx manipulations or tests (#if etc) then it would normally be better as a rexx variable. 9. You can save steps in a macro by using " " to get access to a rexx variable without first having to get a copy with #evaluate. 10. You can use "#define+" & "#evaluate+" instead of #undef. 11. For simple text macros you might want to consider using rexx variables. Depending on how you use the information using rexx variables can be much faster, for example in a #if or #evaluate statement you can remove the need for the substitution syntax and use the value directly. Where you do need to specify substitution use the syntax. #AutoTag Performance 1. Unlike macros, the more autotags you have defined the slower it will be to tag each line. 2. Replacing autotags (defined with #AutoTag) are slow. Only use if no other way and for as few lines as possible. 3. To temporarily reduce your autotag count (remove ones you don't need) you can use the #AutoTagState to hide current definitions before creating your own command. Making good use of named states will simplify this process. #AsIs Performance 1. Unlike macros, the more changes you have defined the slower it will be to tag each line. 2. There is inbuilt optimization for single character "from" text, if possible group these together. This allows the BulkChar2String() routine to be used to greater effect. Tagging must take place in the order you specify so PPWIZARD does not reorder the items to improve performance. Other Performance Hints 1. This may be obvious but PPWIZARD is CPU bound. What this means is the speed of the CPU is directly proportional with the time PPWIZARD takes. If your CPU is twice as fast PPWIZARD will take half the time. Do yourself a favor and use the fastest machine you can find. 2. Under OS/2 you have multiple choices as to which rexx interpreter you can use (DOS has 2 as well). There is the REGINA version as well as traditional rexx (as exists after OS/2 install) or Object Orientated Rexx. If you find things a bit slow it is probably worth your while experimenting. Different interpreters will do some things better than others. You really need to time your particular situation. 3. For common headers etc it may be better if they were not on a network drive. Better yet a RAM disk would be good. Maybe increasing your hard disk cache size could improve things. 4. You might wish to try the /Inc2Cache switch. 5. You might wish to try PPWSORT.H macros rather than SortArray(). 6. 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). So for high performance turn debug off! ═══ 11. e-Zine! Articles ═══ e-Zine! Articles The e-Zine! magazine (http://www.os2ezine.com) as well as the OS/2 Supersite (http://www.os2ss.com/) both use this preprocessor. Chris Wenham (the Senior Editor of OS/2 e-Zine! chris@os2ezine.com) has written a series of articles for e-Zine! which he has allowed me to include in my documentation. The following articles are available: 1. http://www.os2ezine.com/v3n05/htmlpp1.htm 2. http://www.os2ezine.com/v3n06/htmlpp.htm 3. http://www.os2ezine.com/v3n12/dyn3.htm 4. http://www.os2ezine.com/v3n14/dws.htm 5. http://www.os2ezine.com/v4n3/dws.htm ═══ 12. Examples ═══ Examples As well as the many examples that follow, you should also have a look at the PPWIZARD Extensions section as it contains many header files that make excellent examples. ═══ 12.1. Importing fields into multiple HTML documents ═══ Importing fields into multiple HTML documents This example shows how to import a comma delimited file into multiple html pages. The page each record goes into depends on the first character of the "surname" field. This basic process would also work for Fixed Field and Multi Line imports. Example ;---------------------------------------------------------------------------- ; MODULE NAME: IMPORT.IT ; ; DESCRIPTION: Example file of import of a comma delimited file into ; 3 separate HTML files based on the surname field (the ; second field). ; ; ; Imported file looks like: ; ~~~~~~~~~~~~~~~~~~~~~~~~~ ; Dennis,Bareis,Programmer ; Wendy,Buxton,Librarian ; Fred,Nerk,Idiot ; ;---------------------------------------------------------------------------- ;--- Start and end main HTML file ------------------------------------------- MAIN FILE

MAIN FILE

This is a fairly basic example kept simple on purpose to hopefully make things easier to understand. Basically we imported a comma delimited file (could have been fixed or other format) and put the record into a particular html page based on the surname field.

The following imported tables are available:

  1. A - L
  2. M - Z
  3. Others
;--- Define HTML to start the import data files ----------------------------- #define StartsImportFiles \ #output 'p_{$Suffix}.htm' ASIS -\ %\ %\ IMPORTED: {$DESCRIPTION} %\ %\ %\ %\
%\

IMPORTED: {$DESCRIPTION}

%\ %\ %\ #output ;--- Define HTML to end the import data files ------------------------------- #define TrNoRecords #define EndsImportFiles \ #output 'p_{$Suffix}.htm' ASIS APPEND -\ #if {$Suffix} = 'N' -\ <$TrNoRecords><$TrNoRecords><$TrNoRecords> -\ #endif -\
First
Name
SurnameJob
No records
%\
%\ %\ #output ;--- Create 3 output files and fill with start of HTML and start table etc --- <$StartsImportFiles SUFFIX="oth" DESCRIPTION="OTHER"> <$StartsImportFiles SUFFIX="a2l" DESCRIPTION="A to L"> <$StartsImportFiles SUFFIX="m2z" DESCRIPTION="M to Z"> ;--- Prepare for import ----------------------------------------------------- #evaluate '' 'NL = d2c(10)' ;;NL = Newline Code #evaluate '' 'oth = 'N'; a2l = 'N'; m2z = 'N';' ;;No records output yet #define IMPORT_PROTECT_START ;;We don't want imported data "protected" or #output etc won't get executed #define IMPORT_PROTECT_END #define IMPORT_HEADER ;;We will output our own headers #define IMPORT_BEFORE #define IMPORT_AFTER ;;We will output our own trailers #DefineRexx IMPORT_RECORD_FILTER ;--- Which output file should contain this record? --- Char1 = translate(left(Column.2, 1)); if Char1 < 'A' & Char1 > 'Z' then do; Suffix = 'oth'; ;;Not a letter oth = 'Y'; end; else; do; ;--- We have a letter --- if Char1 < 'M' then do; Suffix = 'a2l'; a2l = 'Y'; end; else; do; Suffix = 'm2z'; m2z = 'Y'; end; end; ;--- make sure output will go to correct file --- call WriteLineToTmpImportFile '#if > 1' || NL || ' #output' || NL || '#endif'; call WriteLineToTmpImportFile '#output ^p_' || Suffix || '.htm^ ASIS APPEND'; #DefineRexx ;--- Import the data into the 3 files --------------------------------------- #import Import.CMA CMA "" "First Name" "Surname" "Job" ;--- Close last file -------------------------------------------------------- #if > 1 #output #endif ;--- Finish off 3 html tables and files ---- <$EndsImportFiles SUFFIX="oth"> <$EndsImportFiles SUFFIX="a2l"> <$EndsImportFiles SUFFIX="m2z"> Note that the example above overrides "IMPORT_PROTECT_START" and "IMPORT_PROTECT_END", this allows the generated PPWIZARD commands such as #if and #output to be interpreted rather than simply passed through as data. In some cases this may not be desirable as depending on exactly what you are doing you could put PPWIZARD into a situation where it could "make mistakes" (such as if a field contained '<$'). Although it can be desirable that PPWIZARD interpret macros and expand them if you catered for this in your design, I will demonstrate how you can ensure that they will not be - no matter what. This will demonstrate an alternative approach to using the two "WriteLineToTmpImportFile" lines in the example above and will also ensure that the record line is "protected" from PPWIZARD: ;--- Update what will get written to temp file --- \ AddB = '#if > 1' || NL || ' #output' || NL || '#endif' || NL; \ AddB = AddB || '#output ^p_' || Suffix || '.htm^ ASIS APPEND' || NL; \ AddB = AddB || '' || NL; \ AddA = NL || ''; \ ThisRecordsCodes = AddB || ThisRecordsCodes || AddA; ═══ 12.2. Resource Validation - Local ═══ Resource Validation - Local This example shows how you could ensure that your local resources actually exist (you should also have a look at the validation of remote resources support that PPWIZARD supplies). This helps to eliminate mistakes (its assumed that you won't forget to FTP local resources to the web server!). The example is HTML based but would work for any language or text file where external resources are referenced. While the macros I will show will work, typically everyone has a different way of working which would probably require these macros to be modified, however they are great as a guide. Generic Macro This macro makes no assumptions about your development environment and causes PPWIZARD to fail with an appropriate error message if the resource does not exist. The macro takes 2 manditory parameters, one identifies the full name of the file on the development machine and the other is used for resource identification purposes (when error occurs) and is normally how your HTML references it. The macro is as follows: ;--- Generic check for resource validity routine --- #define CheckResource \ #if stream('{$LocalName}', 'c', 'query exists') = '' \ #Error ^Resource "{$Name}" appears to be invalid. The file "{$LocalName}" could not be located!^ \ #endif Of course you may not wish to abort PPWIZARD for what you consider to be a warning situation, in this case you could use #warning instead. Development Environment Specific Macro In HTML when I refer to an image such as "graphics/fred.gif", the file "fred.gif" exists in the "graphics" directory when the HTML is "run". The image file could exist anywhere on my development machine so I will taylor a graphics validation setup as follows: ;--- Check if Graphic exists ------------------------------------------------ #option PUSH LineContinuation="NULL" ;;Next line ends with continuation char! #define MyLocalGraphicsDirectory C:\PROJECTS\HOMEPAGE\GRAPHICS\ #option POP ;;Restore original continuation char #define MyRemoteGraphicsDirectory graphics/ #define ValGraphic \ <$CheckResource LocalName=^<$MyLocalGraphicsDirectory>{$SNAME}^ \ Name=^<$MyRemoteGraphicsDirectory>{$SNAME}^ \ > The above macros are probably defined in a validation or other common header file. Note that you might wish to use shorter names such as "vlg" for "validate local graphic" etc. To actually test that an image file exists I could use: <$ValGraphic SNAME="fred.gif"> Even the above macro and reference make some assumptions about how I personally wish to use them, this is another reason why everyone would probably "roll their own". An Alternative Way - #1 The problem with the above set of macros is that you have to do 2 operations, the first is to validate the resource and the second is to use it. A better alternative is for the same routine that does the validation to generate the "remote" resource so that the generic macro (lets also change to only warning if resource is missing) becomes: ;--- Generic check for resource validity routine --- #define CheckResource \ #if stream('{$LocalName}', 'c', 'query exists') = '' \ #Warning ^$MR00^ ^Resource "{$Name}" appears to be invalid. The file "{$LocalName}" could not be located!^ \ #endif \ {$Name} ;;"output" the "runtime" file name Now the image based macros might look like: ;--- Check if Graphic exists ------------------------------------------------ #option PUSH LineContinuation="NULL" ;;Next line ends with continuation char! #define MyLocalGraphicsDirectory C:\PROJECTS\HOMEPAGE\GRAPHICS\ #option POP ;;Restore original continuation char #define MyRemoteGraphicsDirectory graphics/ #define UseGraphic \ <$CheckResource LocalName=^<$MyLocalGraphicsDirectory>{$SNAME}^ \ Name=^<$MyRemoteGraphicsDirectory>{$SNAME}^ \ > And to use the macro becomes automatic and simple: Note that I kept the "UseGraphic" macro simple for demonstration purposes, for my purposes I would create a higher level "img" macro which not only validated the file exists but used GetImageHeightWidth() (by default) to automatically calculate the image size. Other "img" tag parameters could be passed as macro parameters (with suitable defaults). A html validation version would be slightly more complex than the above since you would probably wish to also handle the "#location" suffix. The simplest (and maybe best) way to handle it might be just to have a new optional parameter. Another complication is that you would probably look for a local file with the extension ".IT", again exactly how it looks is really a personal preference. An Alternative Way - #2 Under OS/2 there is a free URL checking program which can be given a list of URLs to check. Similar programs will exist for other operating systems. You could create a ".URL" file for each html page and have your macros not only check that everything is fine locally, but add each URL in turn to the new file (deleted at start of build). Later when online and after updating your web site you could run the lists through the URL checking program. Case Sensitivity None of the code shown actually checks the case of the filename so its possible that although the code shows that the file exists locally, if copied to a unix server a "browser" will not find the file. There are a number of changes you can do to check the case or even simpler would be to transfer the files to the unix server in lower case and ensure that you refer to the files in lower case. SiteCopy So as to be very sure that you never forget to correctly update your web site you can use an automated tool such as "SiteCopy" to FTP new or modified files and directories. It will also delete obsolete files and directories. This tool is a bit rough around the edges but it is free and if you provide the developers with constructive feedback they will probably listen. I am using this tool for my site updating. There are OS/2, Windows and other ports of the unix program, the main sitecopy page is at http://www.lyra.org/sitecopy/. ═══ 12.3. SHARING HEADERS - HTML + REXX CGI ═══ SHARING HEADERS - HTML + REXX CGI Whenever you use the #define command to define something you have already decided (whether or not you realise it) the contexts it can be used in. As an example, you could create a definition which expands to a filename surrounded by double quotes, this can only be used in situations where the double quotes are required (or won't interfere). Your other major choice was not to supply double quotes, this then requires you to supply double quotes when used in situations where the quotes are required. Sometimes you can have a mismatch between "languages" which mean that you will need to get "tricky" when creating definitions when a header file is shared such as where a common header file is shared between HTML and rexx code (server CGI script for example). You should understand that PPWIZARD has a /CGI mode, this example does not cover this at all. The rexx CGI script discussed in this example is generated by ppwizard and placed onto the web server for execution. When the /CGI mode is used the header sharing issues discussed here along with the solutions are not relevant and in a lot of cases using this switch may be the simplest solution. Some REXX CGI / HTML Issues 1. Rexx has a limit on the size of a literal. So if you had a standard HTML footer which successfully expands to 2000 characters in a HTML document, simply putting quotes around the text for rexx would result in a 2000 byte literal. The limit is more likely to be around 250 bytes! 2. In a REXX CGI script it may be that some substituted text (macro parameter) may not be known until runtime whereas with HTML you are likely to be able to "hard code" it. 3. Some rexx interpreters also have a limit on the maximum length of a command. 4. There may be a maximum line limit in some rexx interpreters. EXAMPLE - COMMON HEADER ;--- We need to get tricky to use some LONG macros in rexx code ------------- #if ['' = 'REXX'] ;--- We are generating REXX code (take care of OS/2 & REGINA restrictions on lengths of literals and clauses) --- #define RexxAssignTo CgiVar ;;The user must assign macro to this variable #define RexxQuote ' || "'" || ' ;;Used in place of any single quotes #define RexxConcat ';<$RexxAssignTo> = <$RexxAssignTo> || ' ;;End old & start new literal #elseif ;--- We are generating HTML -------------------------------------------- #define RexxQuote ' ;;Simply expand to single quote #define RexxConcat #endif In the above "RexxConcat" is designed to be used "every so often" (within rexx's literal limit). When expanding in HTML it does nothing. In rexx code it finishes off the literal, statement and line then starts another. The "RexxQuote" is designed to be used in place of any single quotes you might wish to output in the expanded text. There should be few of these as you will try to use double quotes everywhere. The following shows how a large macro might make use of the above definitions (note that a lot of external macros are referenced which are not shown): ;--- Define Headings -------------------------------------------------------- #define TitleHtml \ ;--- Start Html ------------------------------------------ -\ -\ -\ <$HtmlDebugNL> -\ {$Title=^{$Text}^} -\ #if '{$OTHERHEADER_TAGS=^^}' <> '' -\ <$HtmlDebugNL> -\ {$OTHERHEADER_TAGS=^^} -\ #endif -\ <$HtmlDebugNL> -\ -\ -\ ;--- Set up Body tag ------------------------------------- -\ <$HtmlDebugNL> -\ <$BodyStandardOs2Warp> -\ <$RexxConcat> -\ -\ ;--- Now output the standard heading bar ----------------- -\ <$BsdHeadingBar TEXT=^{$Text=^Branch Systems Development^}^> #define BsdHeadingBar \ ;--- Put Heading of page into a TABLE -------------------- -\ <$HtmlDebugNL> -\ <$HtmlDebugComment TEXT="Start of Heading Bar"> -\ \ CELLSPACING=0 CELLPADDING=5 -\ > -\ <$HtmlDebugNL> -\ <$RexxConcat> -\ -\ ;--- All left hand images in one cell ------- -\ <$HtmlDebugComment TEXT="All right hand images into 1 cell"> -\ -\ -\ ;--- Output title of this page --------------- -\ <$HtmlDebugComment TEXT="Title of this page"> -\ -\ <$RexxConcat> -\ -\ ;--- All right hand images in one cell ------- -\ <$HtmlDebugComment TEXT="All right hand images into 1 cell"> -\ -\ -\ ;--- End of Heading Row/Table ------------------- -\ -\
-\ -\ -\ ;--- Link To Intranet home page -------------- -\ <$HtmlDebugComment TEXT="Go to Intranet Homepage"> -\ -\ <$RexxConcat> -\ -\ ;--- Link To BSD home page -------------- -\ <$HtmlDebugComment TEXT="Go to BSD Homepage"> -\ -\ <$RexxConcat> -\ -\ ;--- End of left hand images TABLE ---------- -\ <$HtmlDebugNL> -\
-\ -\ <$IntranetImgHeaderAnz> -\ -\ -\ -\ <$BsdImgBsdHome> -\ -\
-\
\ SIZE={$FONTSIZE="+2"} -\ > -\
-\ {$Text=^Branch Systems Development^} -\
-\
-\ -\ -\ ;--- Link to search for phone number --------- -\ <$HtmlDebugComment TEXT="Link to Intranet Phone Search"> -\ -\ <$RexxConcat> -\ -\ ;--- Link to Site Information ---------------- -\ <$HtmlDebugComment TEXT="Link to Intranet Site Info"> -\ -\ <$RexxConcat> -\ -\ ;--- Link to search Engine ------------------- -\ <$HtmlDebugComment TEXT="Link to Intranet Search"> -\ -\ <$RexxConcat> -\ -\ ;--- End of right hand images TABLE ---------- -\ <$HtmlDebugNL> -\
-\ -\ <$IntranetImgHeaderPhone> -\ -\ -\ -\ <$IntranetImgHeaderSiteInfo> -\ -\ -\ -\ <$IntranetImgHeaderSiteSearch> -\ -\
-\
-\ <$HtmlDebugNL> -\ <$HtmlDebugNL> #define Title \ {$Rule="


"} -\ #if ['{$ID=''}' <> ''] -\ ;;User wants to name this posn -\ #endif -\

> -\ {$Text} -\

The following show how one of the macros could be used to generate a title in HTML: <$TitleHtml Text=^The Title of the Page^ FONTSIZE=^+2^> The following show how one of the macros could be used to generate a title in a rexx CGI script (need to be written to stdout): /*--- Get dummy title (set up at compile - of rexx source - time) ---*/ #define+ RexxAssignTo NewLineVar NewLineVar = '<$TitleHtml Text=^$DUMMY$^ FONTSIZE=^+2^>'; /*--- Convert to real title and output (done at CGI runtime) --------*/ NewLineVar = ReplaceString(NewLineVar, '$DUMMY$', RealTitle); say NewLineVar; Note that the ReplaceString() used above is not PPWIZARD's as of course at runtime it is unavailable. My website contains the source code for this and many other handy routines. ═══ 12.4. TEXTEDIT with PPWIZARD ═══ TEXTEDIT with PPWIZARD I have another handy program called TEXTEDIT, it takes a text file as input. PPWIZARD can simplify handling of any text file and this example shows how I have used it to create some "macro" commands that not only simplifies the syntax but checks the return code (TEXTEDIT aborts on error). The code shown here is a small fragment of what I use to completely automatically extract menus, dialogs etc out of Netscape and modify or delete controls, then put the modified resources back into Netscape. DLG102.TE - The MAIN Program ;-------------------------------------------------------- ;--- Edits dialog 102 of Netscape 4.04 "Communicator" --- ;-------------------------------------------------------- ;--- Include header file ---------------------------------------------------- #include "DIALOG.H" ;--- Disable Choose file button --------------------------------------------- <$DisableControlLineGivenMiddle LINE=^<$DLG_CHOOSE_FILE>^> ;--- Disable "Composer" radio button ---------------------------------------- <$DisableControlLineGivenMiddle LINE=^<$DLG_COMPOSER>^> ;--- Thats all Folks! ------------------------------------------------------- <$WriteFile> DIALOG.H - Dialog Specific Header ;--- Include generic stuff ------------------------------------------------- #include "TEXTEDIT.H" ;--- Constants ------------------------------------------------------------- #define DLG_CHOOSE_FILE Choose ~File #define DLG_COMPOSER ~Composer ;--- Disable Control ------------------------------------------------------- #define DisableControlLineGivenMiddle \ ReplaceLines {$COUNT="1"} ^*{$LINE}*^ ^${ReplacedLine}, WS_DISABLED^ %\ if '${Rc}' <> '0' %\ @exit 255 'Could not find a control line matching = "*{$LINE}*"' %\ endif TEXTEDIT.H - Generic Header (for dialogs, menus etc) ;--- Macro to delete a line ------------------------------------------------ #define DeleteLineGivenMiddle \ DeleteBlock ^*{$LINE}*^ ^*{$LINE}*^ %\ if '${Rc}' <> '0' %\ @exit 255 'Could not find a line matching = "*{$LINE}*"' %\ endif ;--- Write changed data to file -------------------------------------------- #define WriteFile \ ;--- Pretty up the final code (easier to read) --- %\ top %\ ReplaceText 9999 "BEGIN" "{" %\ ReplaceText 9999 "END" "}" %\ -\ ;--- Write the file ------------------------------ %\ checkpoint ;--- Find a line ----------------------------------------------------------- #define MustFindLineGivenMiddle \ Find {$COUNT="1"} ^*{$LINE}*^ %\ if '${Rc}' <> '0' %\ @exit 255 'Could not find a line matching = "*{$LINE}*"' %\ endif ═══ 12.5. Rexx Preprocessing ═══ Rexx Preprocessing This program while mainly designed for html processing could be used for most languages. It has specific support built in for the preprocessing of rexx code. Rexx code is by default packed. This makes the resultant ".CMD" file much smaller than the original code and in many cases this would be enough of a reason to use it (although the packing is irrelevant if you then compile the ".CMD" into a ".EXE" using my rexx compiler). Also note that the packing will not speed up the execution of your code although it may slightly speed up the initial tokenization. If you examine the small example, you will notice that I used "#ifdef" commands to determine which parts of the header file I wished to include. You could easily extend this concept to allow debug code to be added only when you wish to debug or have variations on error handling (log the message, ignore it etc). I don't normally define my subroutines as procedures because in my opinion the disadvantages of the way rexx does it outweighs the advantages, my example header file has been written so that the user of the subroutines can determine not only whether they should be procedures but what variables they should expose if they are! 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). ═══ 12.5.1. Rexx Example ═══ Rexx Example The following batch file was used to generated the rexx code: @echo off rem set DEBUG=/debug ppwizard.cmd REXAMPLE.X /output:out\REXAMPLE.CMD /rexx The source files are: 1. REXAMPLE.X 2. REXAMPLE.XH The generated rexx code is: 1. REXAMPLE.CMD ═══ 12.5.1.1. REXAMPLE.X ═══ REXAMPLE.X ;---------------------------------------------------------------------------- ; MODULE NAME: REXAMPLE.X ; ; $Author: Dennis_Bareis $ ; $Revision: 1.0 $ ; $Date: 15 Mar 1999 17:33:38 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.X_V $ ; ; DESCRIPTION: Small example routine. ; ;---------------------------------------------------------------------------- /*--- Want the following comment in the generated output --------------------*/ /* * $Header: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.X_V 1.0 15 Mar 1999 17:33:38 Dennis_Bareis $ */ /*--- I want all my routines to (1) be procedures & (2) Expose some variables ---*/ #define Procedure procedure expose Variable1 Variable2 /*--- Load supporting routines ----------------------------------------------*/ #define INCL_ReplaceString #define INCL_AddCommasToDecimalNumber #include "REXAMPLE.XH" /*--- Make a few changes and Generate the output message --------------------*/ Count = 0; ;;Initialize Counter (this is a PPWIZARD comment) String = ReplaceString('AAAA', 'A', 'B', "Count"); /* Make some changes (this is a REXX comment) */ if Count = 0 then say 'No Changes made'; else say 'Count = ' || AddCommasToDecimalNumber(Count); return(Count); ═══ 12.5.1.2. REXAMPLE.XH ═══ REXAMPLE.XH ;---------------------------------------------------------------------------- ; MODULE NAME: REXAMPLE.XH ; ; $Author: Dennis_Bareis $ ; $Revision: 1.2 $ ; $Date: 09 Sep 1999 13:29:16 $ ; $Logfile: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.XHV $ ; ; DESCRIPTION: Small example header file. ; ;---------------------------------------------------------------------------- /* * $Header: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.XHV 1.2 09 Sep 1999 13:29:16 Dennis_Bareis $ */ /*--- Skip past rexx routines -----------------------------------------------*/ #require 99.249 #ifdef INCL_AddCommasToDecimalNumber /*===========================================================================*/ AddCommasToDecimalNumber: /* Integers Only! */ #ifdef Procedure <$Procedure> #endif /*===========================================================================*/ /*--- Get number return it it we already have commas ---------------------*/ acNoComma = strip( arg(1) ); if pos(',', acNoComma) <> 0 then return(acNoComma); /*--- split at possible decimal point ------------------------------------*/ acDotPos = pos('.', acNoComma); if acDotPos = 0 then acAfterDecimal = ''; else do /*--- There is a decimal component -----------------------------------*/ if acDotPos = 1 then return("0" || acNoComma); acAfterDecimal = substr(acNoComma, acDotPos+1); acNoComma = left(acNoComma, acDotPos-1); end; /*--- Reverse the integer ------------------------------------------------*/ acNoComma = reverse(acNoComma); /*--- Grab 3 digits at a time --------------------------------------------*/ acResultWithCommas = ""; do while length(acNoComma) > 3 acResultWithCommas = acResultWithCommas || left(acNoComma, 3) || ','; acNoComma = substr(acNoComma, 4); end; acResultWithCommas = acResultWithCommas || acNoComma; /*--- Reverse the string and add decimal component -----------------------*/ acResultWithCommas = reverse(acResultWithCommas) if acAfterDecimal <> '' then acResultWithCommas = acResultWithCommas || '.' || acAfterDecimal; return(acResultWithCommas); #endif #ifdef INCL_GetAmPmTime /*===========================================================================*/ GetAmPmTime: /* Fixed length AM/PM time with seconds */ #ifdef Procedure <$Procedure> #endif /*===========================================================================*/ gtCivilTime = time('C'); if length(gtCivilTime) = 6 then gtCivilTime=' 'gtCivilTime; gtNumSeconds = ':'substr(time(), 7, 2); return( insert(gtNumSeconds, gtCivilTime, 5) ); /* Insert # seconds */ #endif #ifdef INCL_ReplaceString /*===========================================================================*/ ReplaceString: /* Too tricky & limiting to set up as procedure */ /*===========================================================================*/ /*--- Get the passed parameters ------------------------------------------*/ rsString = arg(1); rsChangeFrom = arg(2); rsChangeTo = arg(3); rsChangeCntVar = arg(4); /* Passed by reference! */ /*--- Look for the search string -----------------------------------------*/ rsChangeFromLength = length(rsChangeFrom); rsChangeToLength = length(rsChangeTo); rsFoundPosn = pos(rsChangeFrom, rsString); rsChangesMade = 0; do while rsFoundPosn <> 0 /*--- Perform the substitution ---------------------------------------*/ rsString = left(rsString, rsFoundPosn-1) || rsChangeTo || substr(rsString, rsFoundPosn+rsChangeFromLength); /*--- Look for the more occurances of the search string --------------*/ rsFoundPosn = pos(rsChangeFrom, rsString, rsFoundPosn+rsChangeToLength); rsChangesMade = rsChangesMade + 1; end; /*--- Update the change counter and return to the caller -----------------*/ if rsChangeCntVar <> "" then interpret rsChangeCntVar || " = rsChangesMade + " || rsChangeCntVar; return(rsString); #endif /*--- End of header file ----------------------------------------------------*/ ═══ 12.5.1.3. REXAMPLE.CMD (generated output) ═══ REXAMPLE.CMD (generated output) /* * Generator : PPWIZARD version 99.289 * : FREE tool for OS/2, Windows, DOS and UNIX by Dennis Bareis (db0@anz.com) * : http://www.labyrinth.net.au/~dbareis/ppwizard.htm * Time : Sunday, 17 Oct 1999 2:06:48pm * Input File : E:\DB\PROJECTS\OS2\ppwizard\REXAMPLE.X * Output File : out\REXAMPLE.CMD */ if arg(1)="!CheckSyntax!" then exit(21924) /* * $Header: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.X_V 1.0 15 Mar 1999 17:33:38 Dennis_Bareis $ */ /* * $Header: E:/DB/PVCS.IT/OS2/PPWIZARD/REXAMPLE.XHV 1.2 09 Sep 1999 13:29:16 Dennis_Bareis $ */ signal REXAMPLE_1; AddCommasToDecimalNumber: procedure expose Variable1 Variable2 acNoComma = strip( arg(1) ) if pos(',', acNoComma) <> 0 then return(acNoComma) acDotPos = pos('.', acNoComma) if acDotPos = 0 then acAfterDecimal = '' else do if acDotPos = 1 then return("0" || acNoComma) acAfterDecimal = substr(acNoComma, acDotPos+1) acNoComma = left(acNoComma, acDotPos-1) end acNoComma = reverse(acNoComma) acResultWithCommas = "" do while length(acNoComma) > 3 acResultWithCommas = acResultWithCommas || left(acNoComma, 3) || ',' acNoComma = substr(acNoComma, 4) end acResultWithCommas = acResultWithCommas || acNoComma acResultWithCommas = reverse(acResultWithCommas) if acAfterDecimal <> '' then acResultWithCommas = acResultWithCommas || '.' || acAfterDecimal return(acResultWithCommas) ReplaceString: rsString = arg(1) rsChangeFrom = arg(2) rsChangeTo = arg(3) rsChangeCntVar = arg(4) rsChangeFromLength = length(rsChangeFrom) rsChangeToLength = length(rsChangeTo) rsFoundPosn = pos(rsChangeFrom, rsString) rsChangesMade = 0 do while rsFoundPosn <> 0 rsString = left(rsString, rsFoundPosn-1) || rsChangeTo || substr(rsString, rsFoundPosn+rsChangeFromLength) rsFoundPosn = pos(rsChangeFrom, rsString, rsFoundPosn+rsChangeToLength) rsChangesMade = rsChangesMade + 1 end if rsChangeCntVar <> "" then interpret rsChangeCntVar || " = rsChangesMade + " || rsChangeCntVar return(rsString) REXAMPLE_1: Count = 0 String = ReplaceString('AAAA', 'A', 'B', "Count") if Count = 0 then say 'No Changes made' else say 'Count = ' || AddCommasToDecimalNumber(Count) return(Count)