Structure of "Header.def" ========================= 0. Structure ~~~~~~~~~ 1. General 2. The concrete possibilities 2.1 Defining additional headers, modifying headers or deleting headers 2.2 "Wildcards", Variables, String Functions, Numeric Functions 2.3 Bodyheader use/delete 2.4 Introductions, Lines & Signatures 2.5 Text-Body process 2.6 Changing options 2.7 IF conditions 2.8 Flow Control (Gosub, Goto, For/Next, Quit, Do Include) 2.9 Interaction with the User 2.10 Special Instructions 2.11 Debugging 3. Syntax 1. General ~~~~~~~ The exact name of the file can be changed in the options, but the file must be in the "Workpath", with the default being the Korrnews directory. The analysis of the Header.Def statements takes place before any "Bodyheader" entry, thus a header can be defined at the start of the text of the body, with "X-Sowieso=Wert" or "@Sowieso=Wert". Comments are allowed, with each line beginning with ";", "#" or ":". Long lines can be spread over several lines by placing a "_" at the end of all but the last line. To clarify the terms used, here is the structure of a Mail or a News: ----------- I. Header II. Body a) BodyHeader b) Introduction c) text d) Lines e) -- f) Sig ----------- Example: ----------- I. Message-ID: <3375981e.18152730@news.netway.at> Date: Sat, 10 May 1997 16:32:11 GMT newsgroup: de.newusers.questions From: habol@netway.at (Hans Boldrino) ... II. a) X-Homepage: http://home.knuut.de/tgl/ X-Virus: Oh no b) Hello everybody! c) Development of a Newbie At the beginning of February of this year (49), I got caught up to recent times. With an Internet link. But in sequence....... ... d) Greeting and tschuess! Hans e) -- f) de.* short form for "all de-hierarchies and groups" de.all synonym for "de.*" de.!alt short form for "de.* except de.alt" ----------- 2. The concrete possibilities ~~~~~~~~~~~~~~~~~~~~~~~~~~ 2.1 Defining additional headers, modifying headers or deleting headers ------------------------------------------------------------------ The basic function of Header.def consists of easily adding permanent headers to messages by writing the desired entries into the file. As well, the statement "Set Header Designation = value" is allowed and, for legibility sake, also recommended. If the header exists, its' current contents are replaced by the new contents, at its' original position. Conversion of 8-bit characters to ISO-8859-1/QP can be done by Korrnews automatically. Unnecessary headers can be deleted by using "Delete Header Designation" or an empty specification. Example: Set Header X-Newsreader: Forte Agent 32Bit (with Hamster and patches) Set Header X-Homepage = http://www.Ich.bin.toll.de Delete Header X-Mailreader This will replace the X-Newsreader header, insert an X-Homepage header and delete the X-Mailreader header, if it exists. The alternative way looks like this: X-Newsreader: Forte Agent 32Bit (with Hamster and patches) X-Homepage: http://www.Ich.bin.toll.de X-Mailreader: It is sometimes usefull to have multi-line headers, such as for "X-Face" headers. These are defined as follows: Set raw Header X-Face: #0o.eQed-fmU0T,?>{H9_B<%gqE~/fGDJ@[X.]<6obVPh=~9!7-U2x~73]qltjG9F;&/m"-e^.S`B=3[HG$1tjJXq~XDVXVf!r5}EuobNU) MA\WC%"2U8qB3uaW1#U`w9U=`VN/WxZZG^RA+m3&~d"\Vo;dq?eV>WV;Z=6_Q= end The indentation is possible because KorrNews checks the depth of the indentation of the first line and adds the same number of blanks to the beginning of all further lines. Basic headers should be unique so there is no possibility to directly set the 4. From-Header. An exception to this would be the "!RCPT TO" header in the distribution headers of Mails. In order to be able to deal with multiple copies of a header, Korrnews considers two cases: - a "Delete Header ABC" deletes, as opposed to "ABC:", not only the first, but all copies of the ABC header - the instruction "Append Header ABC: blubb" deletes no existing ABC header, but attaches the new header behind the existing one or - if no ABC header exists - corresponds to a "Set Header ABC: blubb" instruction. 2.2 "Wildcards", Variables, String Functions ---------------------------------------- 2.2.1 "Wildcards": Wildcards are always enclosed in percentage signs and permit the use of a header with the setting of another header, a Sig or the like. One can also use string functions, which will be described later, within Wildcards. Wildcard use finds - settings of headers among other things - block statements (signatures, macros etc.) In most other cases "Stringausdrücke" are used; they have the same abilities but are, IMHO, a more meaningful syntax to have. In order to not complicate pure header settings, the Wildcard syntax is still maintained. But now for concrete examples... In order to easily complete the original x-newsreader-header, the following statement is possible: X-newsreader: %Header(X-Newsreader)% (plus Hamster & Korrnews) or to set a In-Reply-To header for XNews, use the following: X-In-Reply-to: %Last(Header(References))% The individual statements such as Last, Header etc. are described later, but the statement "Header" should be relatively obvious. In order to use "genuine" percentage signs in a Wildcard statement, one can either use "raw" items or, for each percentage sign, use two of them consecutively: Set Header X-Parts-Per-Thousand: must be 25%% per litre! If the Stringausdrücke are used, they can be surrounded with "%" Set Header X-Equal: The author is %Header(From)%, states he! one can use the following just as well: Set Header X-Equal: %"The author is " + Header(From) + ", says he!"% 2.2.2 Variables Variable are usable in addition to be able to use - Ausdruck can be longer and used several times with less typing - statuses can be saved in order to be used many times later in IF instructions - strings constructed in order to then be assigned completely to a header. The script language knows only string variables at present; in order to process numbers, they can can be changed at any time into a string by Str() or IStr() and then into a number again with Val(). The definition of a new variable looks like: Set %Gruppe% = Header(Newsgroups) Set %Programmierer% = "Thomas G. Liesner" Set %SeinVorname% = "that is nevertheless the " + Extract("^[^ ]+", %Programmierer%) + "!" Set %ZitierteZeilen% = Str(MatchedLines('^>')) and is used in Wildcards like: X-The-Programmer: is called %Programmierer%! These functions become useful in connection with conditions. 2.2.3 String Functions: Conversions: ------------ Lower(...) changes the string to lower case Upper(...) changes the string to upper case DecodeISO(...) changes an ISO-8859-1/QP encoded header into a "normal" string with 8-bit characters. 8BitTo7Bit(...) changes 8-bit characters into the appropriate ASCII codes (ä => ae, ß => ss, ...) Str(...,...,...) changes the numerischen Ausdruck transferred as the first parameter into a string. The optional second numeric parameter determines the number of characters. The optional third parameter determines the number of post-decimal places; if absent, 2 places are displayed. IStr(...) changes the numerischen Ausdruck into a stringer (without NK places). BoolToStr(Bed.) the result of the transferred condition is converted into a string and thus permits the direct allocation of a condition to a variable. EscRegExp(...) if one uses a header, etc. as a RexExp, one can avoid inadvertent side effects by means of this function, which masks out all special characters ("." => "\.", etc.) Chr(...) changes the numerischen Ausdruck transferred into the appropriate ASCII/ANSI character. Stringer "zerlegen"/"umbauen": -------------------------- First(...) extracts the first item of the string. If the string has commas, the section before the first comma (e.g. newsgroup header with Crosspostings) is extracted. If the string begins with "<" and ends with ">", the first "<...>" pair is extracted (e.g. References header). Last(...) extracts the last item of the string, the opposite of "First" Adress(...) works on - like the following two functions - the Mail address in the From or Reply-To header. Adress tries to extract only the actual address, so "Hans Hirni " returns "abc@def.gh" Name(...) tries to extract the complete name, so "Hans Hirni " returns "Hans Hirni" FirstName(...) Tries to extract only the first name, so "Hans Hirni " returns "Hans" MakeAdress(...,...) combines the passed name and Mail address into a From/Reply-To/To compatible Ausdruck of the form "Name
". Considers special cases in the name (Punkte, Anführungsstriche) Extract(...,...) if the first parameter is a regular Ausdrücken (corresponds to the regular Ausdrücken in Hamster) and is found in the second parameter, the appropriate section is returned, otherwise an empty string is returned. Extract("a.*e", "Hallenbau") returns "alle" CutLeft(...,...) extracts the number of characters indicated by the second parameter from the left of the string passed as the first parameter. CutLeft("Re: Ups", 3) returns "Ups". CutRight(...,...) extracts the number of characters indicated by the second parameter from the right of the string passed as the first parameter. CutLeft("Re: Ups", 3) returns "Re: ". Posting specific: ----------------- Header(...) supplies the value of the indicated header BodyHeader(...) supplies the value of the indicated BodyHeaders, see next point. Full [raw] Header [without Headername1, ...] without parameters and at present only meaningful in certain conditions, returns the entire Headers as a character string. In order to exclude certain headers, the "without" specification can be used. Full [raw] Body without parameters and at present only meaningful in certain conditions, returns the entire Textbody, up to the signature, as a character string. Full [raw] Sig[nature] without parameters and at present only meaningful in certain conditions, returns the complete Signature as a character string. Full Article/Posting/Mail supplies the entire text in "raw" format as a string Filename supplies the filenames of the up-to-date processed postings Path supplies the path in which Korrnews looks for postings Bodyline(...) supplies contents of the xth line of the Textbody; a number or a numerischen Ausdruck must be supplied as parameters. Available lines do not return the delivery of an empty ring. External data: -------------- ReadIniStr() reads the section, keys and a default value (used if the key does not exist) from the INI file passed as a parameter. GetDateTime(...) permits selecting the current time or the current date. The following substitute symbols are permitted in the format string: "yy" or "yyyy" is for year, "m", "mm" for month, "d", "dd" for day, "h", "hh" for hour, "n", "nn" for minute, "ss", "s" for seconds and "hh", "h" for 100ths of seconds. Example: GetDateTime("dd.mm.yyyy") on 1.4.2000 => "01.04.2000" Constants: ---------- CRLF corresponds to a Carriage-Return TAB corresponds to a TAB User inputs: ------------ Input (.,.,.) permits the input of a string by input box. The parameters that must be passed are the dialog title, a request for input and a variable name. Other: ------ Version returns the current version number, however functions only starting from V2.86 2.2.4 Numeric Functions: Additional instructions can be described using string functions and numeric parameters. These can be quite more complex. Naturally pure constants can be used: Delete Bodylines from 10 to 20 As can calculations: If Bodylines > 0 then Do show Info ('Average Characters per Line: ' + _ Str( Len( Full Body ) / Bodylines , 5, 2 ) Calculations can be the basic operations of arithmetic, brackets, the normal arithmetic functions mentioned in the syntax, the power function (^) and the following auxiliary functions: Count (String, String) returns the number of occurrences of the first string in the second string. MatchedLines (RegExp) returns the number of lines which contain the indicated RegExp. Len[gth ] (String) returns the length of a stringer (number of characters). Val (String) changes a string variable to a number, calculations are permitted. Trunc (Number) returns the number without post-decimal positions. Random (Number) returns an integer random number between 0 and Number-1. Bodylines returns the number of lines in the Textbody. Headerlines returns the number of lines in the Header. Siglines returns the number of lines in the Signature. Introlines returns the number of lines in the Intro. 2.3. Bodyheader use/delete --------------------- Bodyheaders are pseudo-headers defined in the Body of the posting. After Korrnews has processed Header.def, it automatically transfers any Bodyheaders into actual headers and then deletes them from the Body. There are quite a range of applications for them within Header.def. Settings using a Bodyheader within Wildcard of the form %BodyHeader(Bezeichnung)% are attainable and thus both variables and "correct" Header can be set. In addition, the main use might be the possibility of controlling Header.def. A small example using the If instruction will hopefully make things clearer: Set %B-Fup%=BodyHeader(Fup) If %B-Fup%>"" If Not (%NG% contains %B-FUP%) Set Header Newsgroups = %NG%,%B-Fup% Set %NG%=Header(Newsgroups) endif Set Header FollowUp-To: %B-Fup% Delete BodyHeader Fup endif This block works on a set Bodyheader named "Fup" and sets "FollowUp-To" according to the headers and completes, if necessary, the "Newsgroups" header for the current group. In order to have Bodyheader be only a temporary function and not really be posted, the statement Delete Bodyheader Bezeichnung prevents the usual transfer into an actual header from taking place. 2.4 Introductions, Lines & Signatures --------------------------------- - Introductions are lines which are inserted at the beginning of the posting, - Lines are lines that are to be inserted between text and signature or to be added to the end of the text - and the signature is a text block inserted at the end of the posting, which is optically separated from the text by means of a separating switch ("-- "). The syntax is alike in all cases, with a special feature that affects only the signature: when adding, Korrnews automatically checks to see if several signatures are contained either in the message or the signature file (by testing SigTrenner including Sigtrenner without blanks) and - if more than one exitsts - selects one randomly. When adding, there are two basic alternatives: New setting or attaching. Which alternative is used depends on whether the "Set" or "Append" statement is used in the call. As well, there are three ways of transferring contents: in the Header.def as a block: ( Set | Append ) [raw] (Sig[nature] | Line[s] | Introduction ) line #1 line #2 line #3 line #4 end Examples: If Header(Newsgroups) contains "test" set Intro ignore - noreply - ignore end endif Set Sig name: Unknown age: I have greeting: Tschuess end in the Header.def as single lines: Set Signature = "my signature is brief" Append Sig = "(or maybe not?)" or in an external file, so that in Header.def there is only a reference: Set Sig from "sigs.txt" Set Lines from "greeting.txt" If the Sig file or the Sig block contains "--" lines, Korrnews interprets this to mean that several Sigs are contained there. Under normal conditions, Korrnews will randomly pick one. In order to use a specific Sig, the following syntax is used: Set Sig #12 from "many_sigs.txt" or If BodyHeader(X-Sigfile) > "" Set Sig # Val("0"+BodyHeader(X-SigNr)) from Bodyheader(X-Sigfile) endif The second case will - if the Bodyheader X-Sigfile was set - analyze a possibly set Bodyheader X-SigNr, set a zero in front of it so that a missing Bodyheader does not cause an error, and converts the Zusammengesetze into a number. With X-Sigfile: jokes.txt X-SigNr: 3 at the start of a Posting, the third signature from "jokes.txt" is attached to the Posting by Korrnews. Please keep in mind the netiquette limit of 4 lines of 80 characters per line maximum per individual signature. By the way, Korrnews makes sure that Lines, Intros and Sigs are not repeated several times by comparing the respective lines with the text which can be used and making with identity no modifications. With Delete Sig Delete Intro Delete Lines can additions be taken back. For queries there is "HasSig" and for special compares there are ChangedSig, ChangedIntro, ChangedLines and Siglines and Introlines, if one wants to know the number of lines in the message. 2.5 Text-Body process ----------------- There are two instructions for modifying the actual text: Do Replace ( first | last | all ) with [ in ( Body | Lines | Sig | Intro ) ] _ [ from ] [ to ] Thus modificatons can be done directly in the text. The search string is a regular string as often is found in Hamster. Example: With Do Replace first ":" to "Frank Mueller wrote in :". In order to limit the area, the first and/or last lines to be examined can be specified - for QP coded texts, section lines are not counted as part of the text. If the Textbody is not to be searched, the search can also be done on Lines, Signature or the up-to-date adjusted introduction block: Set Sig # Einrückung soll von Korrnews # nicht geändert # werden # !! end Do Replace all "^#" with "" in Sig A special case is still "Do Replace ... in %Variable%": with this version, specifing the first/last setting in a variable is possible, which is not feasible with the string function Replace. However, the from/to specification is not considered. A similar function is the instruction: Set macro ... end If one wanted to have, for example, an automatic greeting, one can use the following: Set macro "#greeting#" Tschues, of you Paule! end If then in the Posting War's actually already. #greeting# occurs, the above instructions change it to: War's actually already. Tschues, of you Paule! Another obvious macro would be #spoiler#. One should be sure to make certain that inadvertent replacements do not occur, since the selected macro name could also occur alone in a line. For particularly special cases there is: Set Bodyline(ZeilenNr) = ... for modifying lines, Delete Bodylines xx to xx or Delete Bodyline xx to delete certain lines and Insert Bodyline ZeilenNr = ... to insert individual lines. Delete between ( first | last ) , , [, ] deletes the first or last text block, whose initial line corresponds to the first, and final line to the second, RegExp string. If the first search string is empty and is the first suitable text block to be deleted, everything up to the second RegExp will be deleted. If the second search string is empty and is the last suitable text block to be deleted, everything starting from the first RegExp is deleted. The condition determines whether the the beginning and final line of the block is also to be deleted, and the optional last Stringausdruck is inserted in place of the replaced string. This function is useful, for example, to remove advertising blocks from mailing lists. 2.6 Changing options ---------------- With the instruction Set Option Designation = "Value" the INI options for the current Korrnews run be temporarly (!) modified at any time. However, permanent modifications are not possible in this manner, thus contrary to "Do Write IniStr". If, for example, one normally uses a signature file but doesn't want to use it in a certain group, one would use the following statement: Set Option SigFile = The names of the options are listed both in the HTML help file and also in the Korrnews.ini file. Note: the names of the options can change in future versions of Korrnews. In principle I am for consistancy, but there are no guarranties. 2.7 IF conditions ------------- In order to offer more flexibility, it is possible to make lines dependant upon conditions. The basic form is: If [then] ... [else if ...] [else ...] endif The Else-If and Else branches are optional and it is recommeded that any "..." statements begin with indentations, for the sake of clarity. IF conditions can also be nested, with up to 15 levels permitted. The is also a short version, if one only need to execute one instruction: If then Here are some concrete examples: Fix the Agent bug of not putting quotation marks around the name in From: If Header "From" equals "Thomas G. Liesner " From: "Thomas G. Liesner" endif changes: From: Thomas G. Liesner to: From: "Thomas G. Liesner" Unnecessary Reply-To delete: If Header(From) contains Header(Reply-To) Delete Header Reply-To endif Set a special Reply-To in test groups: If header "newsgroup" contains "test" ; input own FQDN for please. Reply-To=botanswer@ endif Deletes specified BodyHeader only if used: If BodyHeader "HeaderOk" Is Empty ... else ; Tracks smear Delete BodyHeader HeaderOk endif Set group-dependent Reply-To: ; Only if it has the correct Mail address: If Lower(Header(From)) contains Lower("TGL") If Not Header "Newsgroups" is empty ; input own FQDN for please. Reply-To=Answer.from.%First(Header(Newsgroups))@ else Reply-To=Mailanswer@ endif endif Avoid storage in deja.com for certain groups: Set %NG% = Header(Newsgroups) If ("dear ATS" IN %NG%) or (%NG% contains "sex") then X-No-Archive: Yes Post particularly safety-consciously in certain groups: If Header(Newsgroups) = "de.soc.zensur" X-No-Archive: Yes X-PGP: ... endif in some groups use the dnq project Sig: If Not HasSignature and Header(Newsgroups)="de.newusers.questions" Set Signature from dnq-proj.txt elseIf not HasSignature Set Signature from my-sigs.txt endif If the FollowUp-To is set, insert a note above the Sig: Note above the Sig, if one set FollowUp-To: If Header "FollowUp-To" > "" If Header "Newsgroups" contains "," Set Lines X-Post to %Str(Count(',', Header(Newsgroups)))% groups, FollowUp-To %Header(FollowUp-To)% end else Set Lines FollowUp-To %Header(FollowUp-To)% end endif endif The complete outline is in the description of syntax at the end, but here is a list of the boolean special functions: Constant -------- True is for "Yes"/"True". False is for "No"/"False". Postingeigenschaften -------------------- HasSig[nature] returns "True" if a signature exists or was attached by script. Has8BitChars returns "True" if in the Posting there seems to be characters with the 8th bit set, like umlauts, etc. Status queries -------------- Changed returns "True" if past scripts caused major modifications of the Posting. ChangedLines returns "True" if attached lines were defined by "Set/Append Lines". ChangedSig[nature] returns "True" if Sig statements were executed. ChangedIntro[duction] returns "True" if the introduction was set by "Set/Append Intro". User response ------------- Ask (..., ...) returns "True" if the user acknowledges the yes-button of the displayed Messagebox. The parameter is the text which will be used as the title of the Messagebox. Abort (..., ...) returns "True" if the user acknowledges the abort-button of the displayed Messagebox. The parameter is the text which will be used as the title of the Messagebox. Conversion ---------- StrToBool converts a string into a boolean value and permits the Yes/No value to be used as a variable again in a condition by means of "BootToStr". 2.8 Flow Control (Gosub, Goto, For/Next, Quit, Do Include) ------------------------------------------------------ Use the following statement in order to store a function module externally: Do Include This statement is executed while loading the script file, so one could also use the function: Set Sig Do Include "sigs.txt" end The contents of the file are treated exactly the same as though they were originally in the script. The file name - if no absolute path is indicated - is relative to the work directory. With Gosub it is possible to branch into the specified "Sub". Example: Gosub Teil1 Gosub Teil2 Quit Sub Teil1 ... endsub Sub Teil2 ... endsub In order to be able to use parameters, the following syntax can be used: After Gosub Combine "Dies und", "das", %Ergebnis% Gosub Combine %Ergebnis%, "wünsche ich mir", %Ergebnis% Sub Combine (%eins%, %zwei%, Var %Zusammen%) Set %Zusammen% = %eins% + " " + %zwei% endsub the value "Dies und das wünsche ich mir" will be in the variable %Ergebnis%. The "Var" permits modifying an existing variable. String functions or variables and constants are permitted as non-Var parameters. There are two versions of the For / Next statement that can be used to execute an instruction several times: For %i% = 1 to 10 .... Next and For %i% = 1 to 10 do ... The first and final value can be calculations or variables (accessed by "Val(%Variable%)") and with "Step", the increment can be selected at will: For %Countdown% = 10 to 1 step -1 ... Next Loops can naturally also be stacked, however the extensive use of loops is not recommended for simple reasons of performance, since interpretation of the script language is not as fast as a genuine programming language. The instruction "Quit" terminates the script and is necessary when using Subs, since otherwise the error message "unknown quantities instruction 'Sub...'" would be generated. For branching there is: Goto Label which to the branch destination :Label leads. 2.9 Interaction with the User ------------------------- The function Do Show Info [, ] permits output to a Message box, with the script continuing only after acknowledgement. With Do Show Info "A bit excessively quoted, oder?", "Nur ein Hinweis..." for example, one can refer to somewhat excessive quoting. In order to react to user inputs, the following can be used: If Ask ( [, [, [ , ] can be used to call external programs that run synchronously (the script pauses until the called program ends) or asynchronously (the script continues to run parallel to the called program), and any needed parameters may be passed. Thus: Do Run "Notepad.exe", "header.def" would load "header.def" into Notepad. Do ( Open | Print ) is a special case, which opens or prints the indicated document asynchronously with the appropriate application, if the appropriate associations are defined in Windows. Do Sort Header , , ... permits sorting headers to your own taste. Do Sort Header Newsgroups, FollowUp-To, From, Reply-To would ensure that the headers mentioned come first - non-existent headers are simply ignored - with the remaining headers following them in their original order. Do Repair OEQuoting corresponds to the configuration option "Kammquoting repair", and can naturally be used conditionally in contrast to the option: If Lower(Header(X-Newsreader)) contains "outlook" then Do Repair OEQuoting the function is called only if the appropriate header entry refers to OE. Do Write IniStr file, Paragraph, Key, Value is the opposite of ReadIniStr and permits the setting of values in an INI file. 2.11 Debugging --------- If Korrnews encounters "stop", the same (almost) dialog appears as in the case of errors, thus permitting one to see the current values of variables etc. 3. Syntax ~~~~~~ Header.def is organized line by line, so there must be a way to differentiate between block structures, which extend over several lines, and "normal" statements. There are the following block structures: Sub | ... endsub For = to [ Step ] | ... Next If [then] | ... else if | ... else | ... endif ( Set | Append ) ( Intro[duction] | Lines | Sig[nature] [ # ] ) ... end ( Set | Append ) raw ( Intro[duction] | Lines | Sig[nature] [ # ] ) ... end Set [raw] Macro ... end Set [raw] Header Headername: end Set [raw] %Variablenname% ... ... end There are also the following special cases: Do Include this statement executed outside of the normal operational sequence, thus cause accesses to variables automatically errors. :Label Labels may not be placed within If-Blocks/Statements, firstly because the number of Endif's may no longer be right and secondly because the label may not be found. "normal" statements can, if necessary, extend over several lines, which is particularly useful with longer conditions, by ending each line with a "_"; such lines are then internally joined into one large line and then treated like a normal line. The individual items are so defined: Statement := ( [Set Header]
( = | : ) ( ) | Set Header
from | Set = | Set from | ( Set | Append ) [raw] H[eader]
( = | : ) ) | Delete Header
| Do Sort Header
,
, ... | Delete BodyHeader
| ( Set | Append ) [raw] ( Intro[duction] | Line[s] ) = | ( Set | Append ) [raw] ( Intro[duction] | Line[s] ) from | ( Set | Append ) [raw] Sig[nature] [ # ] = | ( Set | Append ) [raw] Sig[nature] [ # ] from | Delete ( Intro[duction] | Line[s] | Sig[nature] ) | Set [raw] Macro ( from | = ) | Do Replace ( first | all | last ) with | Do Replace ( first | all | last ) with [ in ( Body | Sig | Lines | Intro | Header | Header2 | ) ] [ from ] [ to ] | Set Bodyline ( from | = ) | Insert Bodyline = | Delete Bodylines from to | Delete Bodyline | Delete between last , , [, ] | Delete Empty Lines at end | Do Repair OEQuotings | Set Opt[ion] = | Do ( Exec | Run ) [ and wait ] , | Do ( Open | Print ) | Do Write IniStr , , , | Do Show Info [, ] | Do Include | If then | For = to [ Step ] do | Gosub [ ( | ) [, ...] ] | Return | Goto