{#require 2.03} {#include macro jlog.jim}{#define tt/x=x} {#include macro example.jam}\ Jamal=Just Another Macro Language v{version}

Just Another Macro Language v{version}

. . . . . . . . . . . . . . . . . . . . . . . . for HTML


{#define ChapCounter=1}\ {@define ref/x/y=
  • {ChapCounter}. y
    {#define x={ChapCounter}. y}\ {#define ChapCounter={#+ 1 {ChapCounter}}}}\ {@define anchor/x=

    {x}

    }\ {@define Ref/x={x}}\ {@define jsex=j-SEX}

    Table of Contents


    Note: this documentation is rather long to fit a normal HTML page. However I made this still a one pager to ease download, local storage and be it at hand. This documentation is linear, in other words, you can read it from start to end, or even print it, and read it in bed, unless you have something more appropriate for the location.

    Examples appearing in this text are maintained in separate files included into the final html code using {jamal}. Whenever the output of some macro is on display it is generated automatically and included into the html text. This was done to assure that the examples and the results do not contain errors.

    {@comment -------------------------------------------------------------------} {anchor/general} {jamal} is a macro language that reads one or more jam files and generates one output file. The jam files are text files that contain all text content mixed with {jamal} macros. The macros can be used to eliminate repetitive tasks. To simplify understanding and give a jumpstart here is a very simple HTML example: {Example/jam1.txt} This example is actually from the jam file of this page, and is used to create the table of contents as well as to create the titles. The macro define is a built in macro of {jamal} and is used to define "user defined" macros. The macros are always enclosed in some parenthesis, which are {#[} and {#]} by default. You can change them to any string, but that is for later. Built-in macros are preceded with a # or @ character, while user defined macros are not. The macro names are always alpha characters, which is a slight restriction. In other words you can not name a macro a1 or my_macro.

    To be honest user defined macro names can also contain double colons, but that is only for {jamal} extensions written in external Perl modules. See details in {Ref/perlex}

    Macros can be nested. It means that a macro can contain other macros either when it is defined, and also when it is used. Macro nesting has no limit, except physical limitation of memory and time.

    Because macros may distort the formatting of the source text containing the macros {jamal} lets you use new-line characters preceded with back-slash that will not appear in the output file. This lets you type short lines appropriate for your taste and the text editor you use and still have characters on the same line as needed in the output. In short, whenever {jamal} sees a line having a backslash character at the end it chops off the new-line character before processing anything else.

    Macros have two effects. One effect changes the behavior of {jamal}. Example a {#[}#define ...{#]} macro defines a macro, that {jamal} remembers and later this macro can be used. The other effect is that each macro results a string that is put into the output text at the place where the macro is in the original text. In some cases this text is empty. Taking the previous example, the built-in macro {#[}#define ...{#]} results an empty string as well as defines a "user-defined" macro. On the other hand the macro {#[}gen{#]} in the example results the text general.

    Looking at the example above, the first three lines define three macros. The first is the simplest. This macro defines the user defined macro gen. Whenever later in the code we write {#[}gen{#]} it will be replaced by the text general (unless the macro is undefined or redefined later).

    The next two lines define the macros ref and anchor. Both have parameters, and there is another interesting thing that differs from the first macro definition: both macro uses the @ character rather than #. This means that the macros embedded in the definition of the macro are not processed during the evaluation of the macro {#[}#define ...{#]}. In other words, the user-defined macro ref will have the value

  • <li><a href="#x">y</A><BR>{#[}#define x=y{#]}
    If the # were used instead of the @ caracter the value would be
  • <li><a href="#x">y</A><BR>
    The details of this will be discussed in the section {Ref/finepts}. When we call this macro it has several effects. It inserts a table-of-content line into the html code including a link to the anchor, and defines the name of the anchor as a {jamal} macro containing the title of the section.

    Later in the code we can use the macro anchor giving the anchor name as the argument and it will not only insert the appropriate anchor to the text, but will also insert the section title into the html code. This way we eliminate the double typing of the section titles: they only appear in the code once, and the code therefore is easy to maintain. {@comment -------------------------------------------------------------------} {anchor/cmdlin} To use {jamal} you need Perl 5.0. Under UNIX this is quite usual to have this language interpreter installed. Under Windows NT/2K/XP or Windows95/98/ME I use the interpreter from ActiveState.

    You can start {jamal} as any other Perl program. The {jamal} Perl source has the usual UNIX start line {tt #!/usr/bin/perl} that helps you to start {jamal}, but it does not work in case the Perl interpreter is installed in a different directory. Ask for local help.

    From now on I assume that {jamal} can be started using the command:

    $ jamal
    
    (The {tt $} is the command prompt.) The most important use of {jamal} is to start it with the command line:
    $ jamal -h
    
    to print out a short help screen. This will print
    jamal html preprocessor V{version}
    Usage:
    .
    jamal [-options] input [output]
    .
    Options:
    -? or -h               help
    -m file                macro definition file
    -D                     macro define
    -I                     j-SEX directory
    -i                     install j-SEX module interactive
    -0                     suppress output
    -d                     put error message into result
    -t file                trace file
    .
    Your default extension directories are:
    D:\Perl\lib\i386-win32
    D:\Perl\lib
    .
    
    This says that you should type the name of the command at the command prompt. This is {tt jamal} unless you have renamed it. This can be followed optionally by the options, the input file name and optionally the output file name. If the output file name is missing the result is going to be sent to the standard output.

    In the current implementation there are a few options. The option {tt -m} can be used to include macro files before processing the input file. The macros defined in these files are effective when the processing of the input file starts. There can be more than one such macro file specified, and they will be processed by {jamal} in the order they are specified. The name of the macro file should always be a separate parameter for {jamal} following the option {tt -m}, and should never be written together. Therefore

    $ jamal -m macros.jam input.jam output.htm
    
    will first read the file {tt macros.jam}, process the macros and throw away all output that {tt macros.jam} might generate. Then {tt input.jam} is processed and the output is put into {tt output.html}.

    The second option is {tt -D} that you can use to define simple macros on the command line. This can ease the use of jam files that are used to generate several output files. Example {Example/jam23.jam_} and the output {Example/jam23.out} after the file was processed with the command

    jamal -Dincludefile=jam6.jam jam23.jam jam23.out
    
    The macros should be written exactly the same way as they are after the keyword {tt define}.

    For description of the command line option {tt I} see Using j-SEX.

    You can use the {tt O} and {tt d} options to ease debugging of erroneous jam files. Using the {tt O} option {jamal} will not send the output to the screen (to {tt stdout} to be precise) even if no output file is specified.

    Using the option {tt d} {jamal} inserts some of the error messages into the output. This might result a less usable output for further processing, buteasier to debug the {jamal} source.

    The option {tt t} can be used to create a trace file. A trace file contains full debug output of macro evaluation. (For further information see {Ref/trouble}.) {@comment -------------------------------------------------------------------} {anchor/def} Defining and undefining macros is the most common task using {jamal}. Macro definition can be done using the built-in macro {#[}#define ...{#]} macro. After a macro is defined, it can later be used in the file simply enclosing the name of the macro in braces or strings that are defined to be the macro brace string (See the section {Ref/macbra}).

    The following part is precise, hard to swallow, detailed, almost mathematical definition. Try to eat it, but don't panic if you can't: there are easy examples at the end of the section.

    The syntax of define is:

                     {#[}#define name/par1/par2/.../parn/=text{#]}
                     {#[}#define? name/par1/par2/.../parn/=text{#]}
    
    The macro keyword is define. This is followed by an optional question mark. This is followed by one or more spaces followed by the name of the macro name. These spaces are optional if the question mark is present. The macro name can only contain alpha characters from the English alphabet. The names just as anywhere in {jamal} are case sensitive. Macro, define, Define are all valid, and different macro names. On the other hand Macro2, my_macro are not valid macro names, as they contain non-alpha characters, namely 2 and underscore.

    To be precise macro names can also contain double colons, but that is solely for {jamal} extensions written in Perl. See {Ref/perlex} for further details.

    The name of the macro is followed by the formal parameters of the macro. This part is optional. If there is any non-space character between the name of the macro and the equal = sign then it is treated as formal parameters of the macro.

    The formal parameters are followed by an equal sign and the text of the macro follows.

    The list of the formal parameters has the form:

                     /par1/par2/.../parn
    
    The very first character of the parameter list is taken as formal argument separator. In other words this need not be the slash / character. This can be any character. The list of the formal parameters is created taking into account this character as separator. The separator character can, but need not appear after the last formal parameter. Also, when using a defined macro the actual parameter list separator character need not be the same as the character that was used during the definition of the macro.

    Generally speaking the list of the formal parameters follow the syntax of {jamal} parameter list syntax. (See {Ref/listsy} for more details.)

    When a defined macro is going to be used it only have to be enclosed between braces. Spaces are allowed between the name of the macro and the opening brace, but are not allowed between the name of the macro and the list of the actual parameters. The name is immediately followed by the list of the actual parameters, if such list exists. (Actually if there is any space after the name of the macro it is treated as part of the actual parameter-list, and will play the role of the list separator. See {Ref/listsy} for more details.)

    The very first character of the list of the actual parameters is the separator character.

    The parameter string is split up to a list of so many members as many formal parameters are needed. This means that the very last parameter may contain the list separator character.

    During evaluation of the macro the formal parameters appearing in the {tt/text} of the macro are replaced by the actual values of the parameters from left to right.

    Note that the formal parameters can contain any characters, except equal sign, and they can appear anywhere in the {tt/text} of the macro. They can even appear inside of words, in other words there is no usual lexical analysis of the text, parameters are replaced using usual string search-and-replace method.

    When a formal parameter is replaced by its actual value no further replacement takes place on the replacement result, even if a later formal parameter is matched by part or all of the actual parameter. This means that macro definition usage is safe, and does not depend on the formal parameter name.

    An already defined macro can silently be redefined. When using an undefined macro {jamal} outputs a warning to the standard error, and the result of the macro is empty string. The processing continues. This is a defined behavior in case you need it intentionally.

    Since version 2.03 you can put a question mark after the opening brace. This will tell {jamal} that the macro may be undefined and that you are aware of this fact and you do not need a warning. The result of the macro is not altered by the question mark. Spaces are allowed before and after the question mark.

    Let us see a complex example and discuss the above definitions: {Example/jam2.jam} and the resulting text: {Example/jam2.out} The fist two lines include a simple example: a macro definition without arguments. The second definition is what I frequently use to ease {tt/teletype} display of simple words. The formal argument is {tt/x} and this is replaced by the actual value of the parameter on the fourth line of the example. Note that because the {tt/tt} macro requires only one argument it can contain the separator character any times. Even in the first character.

    The last macro is the most tricky. This macro has two formal parameters. These parameters are separated by {tt/&} character. Another tricky point is that the first formal parameter name ends with the letter {tt/le} just as well as the second argument starts with these characters. Usually such a tricky usage is discouraged, here I use them for the sake of the example only. When the actual values are used to replace the formal parameters the two appearances of {tt/apple} are replaced to {tt/lemon}. Now the string is:
    {tt/lemonmon lemon lemon}
    After this action the appearance of {tt/lemon} is replaced to {tt/apple}. However:

    In other words only the last occurrence of {tt/lemon} is going to be replaced, and the final string is as can be seen in the included output above.

    We have not spoken any word so far about the optional question mark after the macro keyword define. This optional sign can help you avoid macro redefinition. You may want to define a macro unless it is already defined. The example {Example jam25.jam} defines the macro a to have the value 3. The second line is a conditional macro that defines a and gives it the value 4 unless a's value is not empty and is defined. The third line defines a and gives it the value 5 unless it is defined. The last line uses the macro a and an undefined macro b.

    The output is {Example jam25.out} You can see that nor the second neither the third line gave a new value to the macro a. The two commands are almost identical and you can use the conditional macro in case you like that, but the third line is more readable.

    You can have spaces between the keyword define and the question mark and you can have spaces between the question mark and the macro identifier. Or you can write them without spaces. However you need something between the keyword and the macro name either question mark or space.

    The use of the macro b results an empty string because this macro was not defined. You can not see on the screen now but believe me (or try to compile the {jamal} documentation) {jamal} did not complain about this undefined macro.

    (This feature was developed according to the request of fstafek@noise.cz) {@comment -------------------------------------------------------------------} {anchor/listsy} Many times {jamal} macros have one or more parameters. These parameters usually stand after the name of the macro in the form of a list. This list is actually a string that usually lasts until the end of the macro or until some special closing character like the equal sign in case of the macro {tt/define}.

    There are such lists for example in the macros

    and these lists are handled exactly the same way. Therefore here we detail how {jamal} treats these lists and later on we can just say parameter list to refer to a string of the syntax.

    {jamal} can not work with the string without splitting up the list into members. We could easily say that the list separator character should be comma, or semicolon. However comma, semicolon, or any other character can appear in a list member.

    The solution that {jamal} follows is that the list separator character should appear before the first list member. In other words: list separator precedes each list member rather than just separating them. {jamal} looks at the very first character of the string representing the list, and knows that this character is the separator character.

    Therefore you should NOT write {Example/jam3.jam} because in this case {jamal} will think that the list separator in {tt/1,2,3,4} is {tt/1} and the list member is the string "{tt/,2,3,4}" and the result is going to be {Example/jam3.out} Instead you should write {Example/jam4.jam} for which the output is exactly what you expect: {Example/jam4.out}

    You can use any character as a list separator character, the only and obvious restriction is that the character should not appear in any list member. (except the trailing one, see later)

    There is also a notable special character: SPACE. When you use space as list separator character you could end up having magical bugs in your code putting double space at some locations and therefore having empty list members without being easily able to recognize it. Therefore {jamal} treats this as a special case. If the very first character of a list is white space (that is usually the name for the group of characters including space, tab, linefeed, form-feed and alike) then {jamal} will use one or more consecutive white space characters as list separators.

    New-line character is also a special character. If the first separator character is new-line then the list is separated by new-line characters, in other words the list members are the text lines. Also an empty line means a zero length string being list member, there is no such trick as in the case of other white spaces. On the other hand, if the first separator character is a white-space but new-line then later new-line characters are treated just as other white-space characters: one or more of them separating the list members.

    Using this feature you can write {Example/jam5.jam} to set the names of the days for your German output.

    When {jamal} splits up the string into a list it may or may not know a-priori the number of list elements. In case of macro {tt/days} {jamal} knows that there are seven arguments and in case of {tt/months} there are 12. When a macro is used the number of actual parameters is known before splitting up the list: it is the same as the number of formal parameters that the macro was defined. On the other hand, the number of list members in a {tt/for} loop, or the list of the formal arguments in a macro definition is known only after the string had been split up.

    When the number of list members is known before splitting {jamal} creates a list with exactly that number of members. If the list needs n parameters then {jamal} stops after it has found n-1 separators and takes the rest of the string the last member of the list. In other words the last member of the list may contain the separator character, but only when the number of list members is known before splitting.

    The lists, where the number of list members is known before splitting:

    In all other cases the number of list members is based on the number of separator characters in the string, and naturally none of the members can contain the separator character. {@comment -------------------------------------------------------------------} {anchor/incmac} A strong point of {jamal} is that it is possible to include files into the code. Using the {tt/include} macro you can include text into the html code that appears in many web page, but you are still able to maintain a single copy of the text.

    There are several formats of the {tt/include} macro to help inclusion of verbatim code, verbatim html, {jamal} macro definitions and {jamal} commands, text.

    The syntax of include is:

                     {#[}#include type filename{#]}
    
    The {tt/type} keyword can be The {tt/filename} parameter is obviously the name of the file. Just in case you are pervert enough wanting to include a file named {tt/pre}, {tt/macro}, {tt/macros} or {tt/verbatim} you can put before and after the file name a quote {tt/"} character.

    The file name can be specified as absolute file name or as a relative file name. A file name is treated as absolute file name if it starts with one of the characters {tt#/}, {tt/\}, {tt/~} or if it starts with some alpha character and the second character is a colon, like in {tt/c:\dos\command.com}

    When a relative file name is specified it should be relative to the file that contains the include macro. At first glance it seems to be obvious, but it is notable when we think of included files including other files.

    File inclusion can be nested any level deep assumed that the system has enough memory, speed and file handle to handle the macros. Systems usually have.

    The file inclusion takes place, when the {tt/include} macro is evaluated.

    When you include a file using the {tt/pre} modifier, the macro is replaced by the content of the file and all {tt/<} characters are changed to {tt/&lt;} as well as all {tt/>} characters are changed to {tt/&gt;}. This is the easiest way to include code examples into an html page. This is actually method that is used to include the jam file examples into this page.

    When you include a file using the {tt/verbatim} modifier, the macro is replaced by the content of the file as the file is. No replacements are done, no macro evaluations are done within the file.

    Using the {tt/macro} or {tt/macros} modifier {jamal} includes the file, processes the macros, even generates the resulting text, but after it replaces the {tt/include} macro with an empty string and throws the evaluation results. The only effect is that all macro definitions, time, date formatting and other "secondary" effects are alive.

    If you are already ahead a bit, you can notice that the {tt/macro} modifier is surplus, as the same result can be reached nesting an ordinary {tt/include} macro into a {tt/comment} macro. (See details in {Ref/finepts}.) However that construct is not recommended to include macros.

    If the {tt/include} macro is used without modification the file is included and processed for macros just as if it were typed into the {jamal} code. {@comment -------------------------------------------------------------------} {anchor/formac} Looping macros are fine points of {jamal}. You can insert repetitive text into html pages. {tt/for} loop has two formats. One format is to repeat text for consecutive integer numbers, the other format is to repeat text for several textual parameter values.

    The first case has the format like:

                   {#[}#for i/ 1 ... 1000 / a[i]=i; {#]}
    
    the second has the format like:
                   {#[}#for i/,this,that,here,there,kakukk/ a[i]=i;{#]}
    
    In both cases the general syntax is:
                   {#[}#for loopvariable/ loopdefinition / looptext{#]}
    
    The macro keyword is {tt/for} followed by one or more space. The next element of the syntax is the loop variable, which is a string of alpha characters. This is optionally followed by spaces and the loop definition comes. The loop definition part defines the actual values for the loop variable. The loop definition is enclosed between the terminating characters. In the example above this character is a slash {tt#/} character, but it can be anything assuming that the chosen character does not appear inside the loop definition.

    When {jamal} locates the loop definition part it takes the first non-space character after the loop variable and uses this character to locate the end of the loop definition.

    To ease readability characters are paired. {jamal} for example knows that the pair of the {tt/(} character is {tt/)}, and it knows other characters as well. The exact pairing definition is:

    When {jamal} finds the first non-space character after the loop variable it takes the pair of the character and uses the pair to locate the end of the loop definition. This finally result a bit more of readability in {jamal} code, example {Example/jam6.jam} resulting {Example/jam6.out} Going back to the {tt/for} macro, the example above shows one possibility for the loop definition. This loop definition contains two integer numbers separated by two or three dots. Using two or three dots is just a matter of taste, there is no difference. The loop will go from the first number to the last incrementing or decrementing the value for the loop variable. The values can be positive or negative.

    The other {tt/for} macro usage uses a parameter list in the loop definition. In this case you can list several values, numerical and textual values, and the loop variable will take all these values. For example {Example/jam7.jam} resulting {Example/jam7.out}

    In case you are good at programming, and followed the text carefully up to now, you can recognize that the definition of the macro {tt/for} is not precise. Looking at the example from above {Example/jam6.jam} you can see that this is either a loop from 1 to 10 as well as a loop for three textual values, namely '{tt/1}', '{tt/...}' and '{tt/10}' separated by space.

    The reality is that {jamal} first tries to interpret the loop definition as a "from {tt/...} to" format and in case it fails goes for the second case which is the parameter list of textual values. If I really wanted to have the above loop for the three textual values I could wrote: {Example/jam8.jam} resulting {Example/jam8.out}

    The final point of the macro {tt/for} is the text of the loop. This text is inserted to the output for each loop replacing each occurrence of the loop variable in the text with the actual value. You should be very aware that the loop variable is replaced at every occurrence, not only where it stands at a place where it can be viewed as a variable. Never have a loop variable named {tt/i} or {tt/L} or something similar or be prepared to end up debugging why {jamal} can not process your {#verbatim tt/{#[}#if ...{#]}} macro (as I did, when the {tt/i} from {tt/if} was replaced to {tt/0, 1, ...} in the loop). {@comment -------------------------------------------------------------------} {anchor/selmac} There are cases when you would like to easily extract a member of a {jamal} parameter list. Such an example can be a list of week day names both in English and German, like: {Example/jam24.jam} resulting {Example/jam24.out} If you think that this example is not the best one, you are right. But in many cases you will soon need the macro {tt select}.

    The formal definition of the macro is

            {#[}#select LIST{#]}
    
    where {tt LIST} contains two elements. The first element should be a numeric value and the second should itself be a {tt LIST}, something like:
            {#[}select/n/LIST{#]}
    
    The value of the macro is the nth element of the {tt LIST}. The index starts at zero as in most modern programming languages, in a way as was shown in the example above. {@comment -------------------------------------------------------------------} {anchor/ifmac} Currently there is only one conditional macro implemented in {jamal}. This is the {tt if} macro. The precise syntax of the macro is:
                   {#[}#if/test/text if test is true/text if test is false{#]}
    
    The most precise definition is that the keyword {tt if} is followed by a {jamal} parameter list according to the syntax described in {Ref/listsy}.

    {jamal} first evaluates the first element of the list and if this value is true the resulting text of the macro is the second element of the list. If the value is false the resulting string is the third element of the list.

    A very simple example uses this macro to automatically generate a link to the previous chapter in an imagined document: {Example/jam16.jam} and the result {Example/jam16.out} You can see that {jamal} automatically calculated the serial number of the previous chapter and also noticed when there was no previous chapter. {@comment -------------------------------------------------------------------} {anchor/exprmac} {jamal} is not a language that you are going to write numerical simulation. However there are macros that support some numerical calculations. The name of these macros is usually a one or two character operation sign followed by the list of arguments. The list follows the {jamal} parameter list syntax. The operators currently implemented are:

    File operators can be written lower case or upper case. When the lower case form is used the file name is treated as relative to the input file. The upper case letters treat the file name as relative to the output file. Absolute file names can be used with either upper or lower case version.

    A simple example calculates the expression (6+3)*12-5/8: {Example/jam17.jam} and the result {Example/jam17.out} which you are obliged to check using pencil and paper! {@comment -------------------------------------------------------------------} {anchor/dirmac} One of the most powerful features of {jamal} its capability to automatically list files from a directory. Using the {tt/dir} macro you can generate text in a loop for files in a directory.

    The macro {tt/dir} is similar to the macro {tt/for} in the sense that this also does a looping inserting text to the output several times.

    The format of the macro {tt/dir} is

                 {#[}dir/directory/pattern/text{#]}
    
    The parameter {tt/directory} gives the directory, {tt/pattern} gives a selection option and {tt/text} is repeated for each selected file.

    The directory can be absolute or relative to the file that contains the macro {tt/dir} or relative to the output file in case option {tt o} is used. The {tt/pattern} can contain a list of options, and a usual file pattern, like {tt/*.txt} to select text files.

    The {tt/text} can contain any text and macros, and will be inserted to the output for each selected file once. This text can contain so called looping macros to display name, extension, date, time, size or other feature of the actual file.

    The separator character can be slash or any other character according to the parameter list syntax definition (see {Ref/listsy}), with the exception that {tt/text} can contain the separator character any time, only the first two such characters are taken into account to get the parameters {tt/directory} and {tt/pattern}.

    Before going on, let us see an example: {Example/jam9.jam} and the output {Example/jam9.out} This is a very simple example just to give you a brief feeling what macro {tt/dir} is all about. The above example says that {jamal} should read the current directory, select all files that match the pattern {tt/*.jam} and list them line by line.

    In the text of the macro we used the predefined loop macro {#verbatim tt/{#[}$file$name{#]}}, which is replaced by the name of the actual file for each loop. The loop macros are all starting with the dollar {tt/$} sign, and only evaluated when being in a loop. In other words there is no need to start a {tt/dir} macro using the {tt/@} character only to protect the loop macros from evaluation. (But you should indeed use the {tt/@} character if you have other nested macros to be protected. For further details read {Ref/finepts}!)

    The list of all available loop macros, and their meaning:

    The {tt/pattern} part of the macro {tt/dir} can not only contain file pattern, but also options. For example: {Example/jam10.jam} says that the directory listing should be done for files matching the pattern {tt/*.jam}, only the non-zero length files ({tt/-s}) should be listed, and the files should be sorted by name in decreasing order ({tt/-Snd}).

    The options are always before the pattern, and can be written together like {tt/-sSnd} , or separated, as they are in the example above.

    The options can be

    If the {tt/h} option is not used all references to html parameters of the files result empty string. However if the sort option says that the files should be sorted according to html title, the {tt/h} options is automatically switched on.

    The macro {tt/dir} can be used inside other {tt/dir} and this way you can create listing of files which are in directories in a directory. For example you can list all files that are in some directory under directory {tt/doc}: {Example/jam11.jam} This example is quite complex, and in case there are certain points that you do not understand, please read the section {Ref/finepts} and return here afterwards.

    The first {tt/dir} starts with the character {tt/@}, which means that the inner {tt/dir} is evaluated when the outer {tt/dir} is evaluated and not before. If we used the {tt/#} character instead the outer {tt/dir} would see an empty string in place of the inner {tt/dir}. The reason for it is that in case of {tt/#} the macro evaluation goes from inside to outside, and because there are no files in directory doc/{#[}$file$name{#]} (just as there is no such directory at all with such a weird name) the result of the inner {tt/dir} is empty string.

    As the outer {tt/dir} is preceded with the {tt/@} character the inner {tt/dir} macro is evaluated when the outer loop have already created text for each directory under the directory {tt/doc}. Assume that there are directories {tt|jamal, dummy1, dummy2} in the directory {tt doc}. Then the outer {tt dir} macro will result the text {Example/jam12.jam} The macro {#[}$file$name{#]} is resolved in the directory parameter, but is not resolved inside the texts of the macros, because the {tt null} macro have protected it. The result of the example: {Example/jam11.out} should eventually be the same as {Example/jam12.out} created by the second, half evaluated macro. {@comment -------------------------------------------------------------------} {anchor/datemac} You can easily insert time and the date values. The macro {#[}#time{#]} and {#[}#date{#]} insert the actual time and date, like {#format date=MONTH DD, YEAR DAY}\ {@define EXAMPLETIME=\

    This document was last updated {#date} {#time}
    }\ {EXAMPLETIME} The format of the representation is flexible and can be changed easily using the {tt days}, {tt months} and {tt format} macros.

    {jamal} stores the names of the days and moths in an array and uses these names to display a date. The default names are English. In case the generated output is going to use some different language you can redefine the array saying: {Example/jam13.jam} Including the file {tt jam13.jam} here {#include macro jam13.jam} and displaying the above time example says: {EXAMPLETIME} Notice that the name of the day and the month is already in Hungarian. When a time or date value is displayed (like the time and date values of a file in a {tt dir} loop) the values are formatted according to the build in date and format string. There are two such strings: one for the time and one for the date values. You can set these strings using the macro {tt format}.

    The syntax of the macro {tt format} is:

                  {#[}#format xxx=format string}
    
    where {tt format} is a keyword, {tt xxx} can be {tt date}, {tt time}, {tt am} or {tt pm} and {tt/format string} is the formatting string. When displaying date or time value {jamal} takes this formatting string and performs several substitutions, as follows: When {tt am} or {tt pm} is used it is actually replaced by the string which can be changed using the macro {tt|format am} and {tt|format pm}. Therefore you can say: {Example/jam14.jam}

    After the time value is created using the substitutions above the resulting string is evaluated in case there are embedded macros. Therefore it is possible to write the following: {Example/jam15.jam} and including the above as a macro{#include macro jam15.jam} the time example {EXAMPLETIME} Note that there is no significant difference between time and date. You can include formatting elements like {tt YEAR} into time formatting, and elements like {tt hh} into date formatting. Bot {tt time} and {tt date} macros are based on time values which are precise up to seconds. {@comment -------------------------------------------------------------------} {anchor/finepts} Read this section to understand the bits and pieces how {jamal} macros are evaluated, how macros are recognized by {jamal} and what order they are evaluated.

    This section is more definitive than explanatory. Here we describe how {jamal} internally works and give only less explanation what rules to follow when writing compound and nested macros.

    When {jamal} starts to process a text it first tries to locate the first macro in the text. He does it searching for the macro opening string, which is usually the character {#[}. When it finds such a string {jamal} appends all processed text to the output and starts to search the end of the macro. He does it looking for the macro closing string, which is usually the {#]} character. While searching {jamal} keeps track of the embedded macro opening and closing strings.

    When this is done {jamal} has the macro in an internal buffer. If the macro starts with {tt #} character or is a user defined macro {jamal} evaluates the macros that are embedded in the macro following the same steps as it followed until now. This is a recursive call and for the sake of reference we call it pre-evaluation. If the macro starts with the {tt @} character no pre-evaluation takes place.

    The next step is to evaluate the macro itself. This is done in a separate procedure that defines the behavior of the {jamal} macros. These check the syntax of the macro, look for parameters, look up user defined macros if necessary and generate some text. The final step during this calculation usually is searching again for embedded macros in the resulted text and evaluating them using recursive call. Let us call it post-evaluation.

    The process formalized: {Example/algorith.txt} There are some exceptional macros that do not evaluate the result again to resolve macros that were generated evaluating the macro. These are

    {@comment -------------------------------------------------------------------} {anchor/null} The {tt null}, {tt comment} and {tt verbatim} macros serve special purpose to alter the evaluation order of macros. Usually macros are parsed from outside to inside and evaluated from inside to outside when macros are nested.

    When a macro is evaluated first all embedded macros are evaluated before taking care of the macro itself unless the leading character of the macro is {tt @}.

    When a macro is evaluated {jamal} tries to find again embedded macros in the result to assure that there remained no macros unevaluated.

    Let us look at the macro that we use in this document to include examples. {Example/example.jam}

    null

    We did not use the {tt @} character to start the definition of the macro {tt Example} because there are embedded macros like {tt ExampleColor} which are supposed to be evaluated before the definition takes place.

    On the other hand the macro {tt include} had to be protected from evaluation otherwise {jamal} could try to open a file named {tt file} which is unlikely to exist. (And if it existed examples would tend to be boring a bit.)

    To protect the macro another macro {tt null} was used. This macro does nothing else but results the body of it without post-evaluation.

    When the body of the macro {tt define} is evaluated before the definition takes place, the macro {tt null} is evaluated and it results the string {#[}#include pre "file"{#]}, which is appended to the body of the macro {tt define} without further evaluation.

    When the macro {tt define} is evaluated it has got the {tt include} in it intact. The post-evaluation does not evaluate the macro {tt include} either, because this text does not get to the output of the macro {tt define}. The output of the macro {tt define} is empty string. On the other hand the macro {tt include} together with the other lines gets into the value of the defined macro: {tt Example}.

    When the macro {tt Example} is called it is evaluated, all formal/actual parameter substitutions take place and after this, the post-evaluation of the macro {tt Example} does evaluate the macro {tt include} having the actual file name as an argument due to formal/actual parameter substitutions.

    comment

    The last line of the example shows a comment. This comment is indeed a macro, but as the start character is {tt @} the macros that might happen to be nested in it will not be evaluated in pre-evaluation and by the defined behavior of this very macro no post-evaluation will take place.

    There could be an interesting, but (warning! personal opinion follows!) perverted use of the macro {tt comment}: you can use this macro to emulate the effect of the macro {tt/include macro}. {Example/jam21.jam} and the output {Example/jam21.out}

    verbatim

    The macro {tt verbatim} can be used to prevent post-evaluation of user defined macros. The macro {tt verbatim} has a special syntax:

    {#[}#verbatim user-defined macro{#]}
    
    The user defined macro should be written after the keyword {tt verbatim} separated by one or more space together with its arguments if any exactly the same way as if it were not verbatim. When {jamal} sees the {tt verbatim} prefix it passes evaluation to the user defined macro, but also tells it not to do post-evaluation. If the macro {tt verbatim} is used with the {tt @} character pre-evaluation is also prohibited. In case only pre-evaluation is to be prohibited the arguments of the user defined macro should be protected using the {tt null} macro. Example {Example/jam22.jam} and the output {Example/jam22.out} The first output line is resulted as pre-evaluation transformed {tt apple} to {tt alma} and post-evaluation transformed {tt alma} to {tt szilva}. Note that post-evaluation already sees the macro opening and closing strings around the string {tt alma} as the {tt [} and {tt ]} macros were evaluated during pre-evaluation.

    The second version does not perform post-evaluation, and therefore {tt alma} remains {tt alma}, bracketed obviously.

    The third line does not evaluate neither before, nor after the evaluation of the macro {tt tt}.

    The last line evaluates the {tt define} macro before processing the macro {tt tt}, but protects {tt apple} from pre-evaluation using the {tt null} macro. However this macro is evaluated after the macro {tt tt} was evaluated during the post-evaluation and the result now is {tt jabloko} as the macro {tt apple} was redefined during the pre-evaluation of {tt tt}. Clear? {@comment -------------------------------------------------------------------} {anchor/macbra} The macros in jamal usually start with the character {#[} and finish with the character {#]}. This is a good choice for HTML crafting, but may not be appropriate for other languages. Therefore {jamal} provides a macro to redefine the opening and closing string. You can use any string to start and to end a macro assumed that they are different.

    The syntax of the macro that redefines the macro bracket strings is:

                   {#[}sep/start string/end string{#]}
    
    The keyword {tt sep} is actually should be followed by a list of syntax "{Ref/listsy}". The first element of the list will be used as macro start string and the second as a macro end string. The simple example {Example/jam18.jam} and the output {Example/jam18.out}

    The first line of this example shows nothing interesting. The second line sets the macro start and stop strings are set to {tt Start} and {tt Stop}. The third line that follows already uses these separator strings and therefore result a different output than the first line. On the third line the {#[} and {#]} characters are appear as normal characters and {jamal} just outputs them.

    The next line redefines the separators to be {#[} and {#]} but the reverse order. This is used on the last line.

    Care has to be paid when using the macro {tt sep} inside other macros. As macros are usually parsed from outside to inside and evaluated from inside to outside the redefined separators might have undesired effects. The thumb rule says that the macros should be terminated using the pair of the opening string. In other words, if a macro was opened using the string {tt xxx} and the pair of it is {tt yyy} then {tt yyy} should be used to close the macro even if an embedded {tt sep} macro redefines the opening and closing strings.

    To make it even more confuse here is an example: {Example/jam19.jam} When {tt sipsep} is defined a {tt sep} macro is evaluated and it changes the separators to {tt [} and {tt ]}. Even though the {tt define} is closed using the conventional {#[} character as it was opened using the character {#]}.

    The define on the next line already have to use the {tt [} and {tt ]} characters as separators. The embedded {tt sep} macro in this case however is not evaluated when {tt supsup} is defined, because the leading macro character is {tt @}. On the other hand, when {tt supsup} is used, it results the string {tt puspus} and as a side effect resets the macro separator strings. The output file is: {Example/jam19.out}

    Try to imagine what happens when you extend the last line of this example with the {#[}supsup{#]} macro call. What will the result be and why does {jamal} complain about malformed macro? {@comment -------------------------------------------------------------------} {anchor/macbr} Sometimes you need a quick way to include {#[} or {#]} to the output, but in case it happens only at a few locations it does not worth the effort to change the macro separator characters using {tt sep} to a different value and setting it back.

    For such situations {jamal} introduces four macros. See the example {Example/jam20.jam} will result {Example/jam20.out} The {tt [} macro closed between macro start and end strings and preceded by {tt #} or {tt @} character return the actual macro opening start string. {tt ]} returns the macro end string the same way. Just in case you happen to set the macro opening and ending strings to these characters {#[} and {#]} work the same way. {@comment -------------------------------------------------------------------} {anchor/require} Since V2.0 of {jamal} there is a macro {tt require} to check the version of {jamal}. This macro takes one numerical argument, and in case this argument is larger than the version of the procesing {jamal} it generates a fatal error.

    This macro can be used to inform {jamal} on the minimal version the source file requires. Unfortunately {jamal} V1.0 does not know this macro and does not stop. However even {jamal} 1.0 will complain about bad macro format.

    This macro requires a certain {jamal} version and has nothing to do with the versions of any {jsex} modules.

    Requiring a certain version that the file was written for is a safe operation and it allows later {jamal} versions to modify their behaviour according to the requested version. Some versions of {jamal} might behave different from earlier versions and may choose to retard the bahaviour if an earlier version is required by the source file. Such a feature is NOT implemented in the current version.

    There are some certain features between 2.0 and 2.01 that behave different. In version 2.0 the macros {tt and} and {tt or} have lost the first argument. This was a bug and therefore requesting version 2.0 does not produce the buggish behaviour using {jamal} V2.01 or later. {@comment -------------------------------------------------------------------} {anchor/trouble} Simple macros are simple to write and they usually work fine. However at some point of time you will meet a macro you wrote that does not work. It either does not produce the output you needed or {jamal} complains about some error.

    Such an error comes from {jamal} or from your source. The second case is the more likely. This is not because I wrote {jamal} bug free, but much rather this is what I experience. Many times I was hunting bugs in the Perl source of {jamal} and after a few minutes (or few hours if I am honest) I found out that {jamal} worked well. Only the macro I wrote was wrong, or my expectation were wrong. This is especially true for nested macros with sophisticated macro evaluation order.

    Rule numero uno: If you think having found a bug in {jamal} do not hesitate to send me a bug report. If this is really a {jamal} internal bug, it helps me to correct. If it is not, I can help you telling what was wrong and your report can help me to improve the documentation. If you misunderstood something: the problem is with the documentation and not with your brain.

    If {jamal} complains about some error it tries to be as specific as it can regarding the type of the error and the location. {jamal} displays four lines for each error.

    1. The message of the error in English.
    2. The parameter of the error message if there is any such beast. This is usually the fragment of the source code that caused the error. For on-screen readability the fragment is truncated to 20 characters and if truncation was done ellipses are added to the parameter. Also the new-line characters are substituted with {tt \n} character pairs to ease readability.
    3. {jamal} displays the file and the line number where it found the error. (See notes later!)
    4. {jamal} displays the Perl source file, package and program line information. This is usually not interesting for you unless you are developing or using {jsex} packages.
    You can locate the error in the source file and correct it. In some cases {jamal} continues processing the file even after an error and might result the wanted output. Do not be satisfied with such a result! Correct the source until {jamal} processes it without error or warning messages. If you have a file that {jamal} translates correct but displays error messages you have an output which is not guaranteed. Having many of such large files in a project can result deep problems when you want to upgrade {jamal} to a newer version. {jamal} might behave different.

    But how to debug syntactically correct but misbehaving macros? Macros do not execute, they are just replaced internally in {jamal}'s memory and only the final result is sent to the output file.

    If you experience macro evaluation problems you can ask {jamal} to produce a "trace" output using the option {tt -t}. The file you name with this option will be overwritten by {jamal}'s trace report.

    Each line in the trace file has four columns. Columns are separated by colons. The firs column is the line number of the source file that the trace is displaying. The second column is type of the line saying that {jamal} is tracing a {tt M} macro evaluation {tt L} lines without macro evaluation (also before and after macro evaluation) or some macro was {tt D} defined.

    NOTE: There is a known bug regarding the line numbers: {jamal} preprocesses the input before anything else removing backslash escaped new lines. Line number calculation is done afterwards. This means that the line numbers {jamal} displays should be treated escaped new-line characters removed from the source file. {@comment -------------------------------------------------------------------} {anchor/perlex} After {jamal} V1.0 was released there was a huge demand for several extensions. Users wanted to have macros that can not be defined using {jamal}'s {tt define} macro but are too specific to include them into the {jamal} language. Some user even modified the source of {jamal}.

    Putting all requested macros into {jamal} would have led to a huge, slow and unmaintainable macro processor.

    On the other hand user modification of {jamal} would lead to several incompatible versions.

    The solution is that {jamal} became extendible using Perl modules since version 2.0. These extensions can be very simple and at the same time perform useful tasks. As they are {jamal} Simple EXtenson modules I call them j-SEX modules.

    To use a j-SEX module you have to install the source of the extension and be familiar with the {jamal} built-in macros {tt use} and {tt with}.

    To write j-SEX modules you should be familiar with the language Perl, and should also know Perl modules.

    As j-SEX modules written in Perl are an elaborate topic, here we included two documents.

    There is a built-in macro called {tt INC} that can be used to specify the location of the extension modules. The extension modules usually are in a directory called {tt jamal} under the Perl library directory. The list of the available library directories are stored in the Perl array {tt @INC}, and is displayed by the {jamal} help screen (Type {tt/perl jamal.pl -h}.)

    There is a command line option to specify additional directories as well as the macro {tt INC}.

    The macro {tt INC} has one argument, the directory where the directory named {tt jamal} containing the extension modules is. The name of this directory can be absolute or relative to the input file. This will be {tt push}-ed onto the array {tt @INC} in Perl so the next time Perl looks for a module it will look for this directory as well. {@comment -------------------------------------------------------------------} {anchor/jsexinstall} Since version 3.0 there is a new command line option to {jamal} {tt -i}. Using this option you can easily install j-SEX module on the system you run {jamal}. You should start {jamal} interactive typing {tt 'perl jamal.pl -i xxx.pm'} to install install the module {tt xxx.pm} or just {tt 'perl jamal.pl -i'} to install all j-SEX modules that can be found in the current working directory.

    The option works interactive. Before doing anything it lists all the files it is going to install and it also lists the possible locations where the module can be installed. You can choose one location and {jamal} will copy the module into the selected directory.

    You can specify any number of modules following the option {tt -i}. You have to have appropriate privilege so that {jamal} can write the directory where the module is to be copied to. This usually means that you have to be {tt root} or {tt Administrator} on the system you run {jamal} on.

    After you installed the j-SEX module you should check that the installed files have the appropriate permissions. {@comment -------------------------------------------------------------------} {anchor/history}
    versionDescription
    1.0Primary {jamal} version
    2.0{jsex} interface defined
    2.01Numeric file operation -t
    bug fixing numeric operation handling
    operator {tt not} was missing (this was bug not having that operator)
    errors now display source line numbers
    trace file output is available
    3.00j-SEX module installation included
    {@comment -------------------------------------------------------------------} {anchor/future} {jamal} tries to be powerful, easy to use, complete and perfect. On the other hand the few thousand years of human history taught us that nothing powerful is easy to use, and nothing made by men or women is either complete or perfect. I did my best.

    There are certain features that {jamal} could include, but does not. There was a certain time during development, where introduction of new features was stopped, and development started to focus on bug elimination. Here I list some features that {jamal} does NOT support, but I think could be useful and might be introduced in version 2.0

    {jamal} current version is {version} and all new versions between this one and the next major version will only contain bug fixes and no major new features.

    WARNING: Some features of {jamal} current version might change in future versions in a way being incompatible with current version. Such changes are tried to be predicted and listed here.

    New features will be introduced according to your response and inquiries. See section {Ref/feedback}.

    {#define feature/FEATURE=

    FEATURE

    } {feature|Features} There are currently no features in my mind that I think should be implemented into {jamal}. Give me ideas. {@comment -------------------------------------------------------------------} {anchor/feedback} You can reach me by electronic mail peter@verhas.com.

    Please note that supporting {jamal} is not something that I am paid for. This imply that my answering capability is limited and has priority lower than job and family. Even though: if you have any note drop me a mail. And please, please read the documentation. (This seems to be a silly request. You are doing it, aren't you?)

    I highly appreciate bug reports, but as usually try to be specific, provide the shortest possible example demonstrating the bug.

    I appreciate modules submitted for publication. I am going to create a repository for {jsex} modules.

    Ideas, comments appreciated. Send me your tipps.

    Flames: thank you, no.

    Telling me that generally my English is not good enough does not carry information for me. I know. And on the other hand I speak English probably better than you do Hungarian. But tell me my mispellings in the documentation. I will correct. {@comment -------------------------------------------------------------------} {anchor/tipps} A short collection of tipps, how to use {jamal} effectively. These are not hardwired rules to follow. Matter of taste. {@comment -------------------------------------------------------------------} {anchor/author} Péter Verhás
    HOME PAGE

    {@comment -------------------------------------------------------------------} {anchor/compet} There are other software products that aim the same or similar goal. Here is a partial list. If you know any other software not listed here, please let me know!

    {@comment -------------------------------------------------------------------} {anchor/legal} This software is provided on an "AS IS", basis, without warranty of any kind, including without limitation the warranties of merchantability, fitness for a particular purpose and non-infringement. The entire risk as to the quality and performance of the Software is borne by you. Should the Software prove defective, you and not the author assume the entire cost of any service and repair.

    Any statement, assumption expressed or implied in this document, in any attached document, program source code, or in any other information source associated with this program, belong to the author, and might not reflect the views of anyone else.

    The development of the program was sponsored by no one. I have done it in my free time at home using resources that I have legally purchased, including hardware and software.

    You are free to use and distribute {jamal} as far as your actions are in line with the GNU General Public License. I would also appreciate if you could include a reference text on one or more of the pages that you create on a site using {jamal}. This can be done using the predefined macro {#[}reference{#]}.
    {reference}