.NH 1
Programming in OCL
.\"{{{  introduction to this chapter
.LP
This chapter describes OCL (Origami control language) and gives some
examples to show how powerful it is.  OCL is a programming language
offering capabilities to use conditional statements, subroutines, loops,
variables and recursion.  The keybind program compiles human readable
OCL source code to a binary which will be interpreted by Origami.  The
functions described in the chapter explaining keybindings are very
simple OCL statements.
.\"}}}
.\"{{{  OCL syntax and semantic
.NH 2
OCL syntax and semantic
.LP
This sections describes all other OCL elements.  It is assumed that
you are familiar with other programming languages.  You will find
examples in a later section.
.\"{{{  marks
.NH 3
Other marks for folds
.LP
(defmark <name> ( <mark1> <mark2> <mark3> <mark4> ))
.SP
This option puts data in the rcfile, so that origami can switch to other
marks for folds if it is invoked with commandline option `\-mname'.  The
format for <mark> is:
.DS
( <single-char> <single-char> <single-char> )
.DE
where <single-char> is a ``"x'' definition like in (keybind ... ).
The meanings of <mark1> ... <mark4> are:
.DS
<mark1> begin of fold, standard is `{\&{\&{'
<mark2> closed fold, standard is `.\&.\&.'
<mark3> name of filed/attached fold, standard is `:\&:\&:'
<mark4> end of fold, standard is `}\&}\&}'
.DE
.\"}}}
.\"{{{  Subroutines and macros
.NH 3
Subroutines and macros
.\"{{{  defmac
.LP
(defmac <name> (<statement> ... ) )
.SP
The Origami operations defined in (<statement> ...  ) are furthermore
reproducable as <name> too, so you can use them to define other macros.
Remark that these are really macros, they are only copied to the calling
macrodefinition.  Inside of (<statement> ...  ) you are allowed to use
<name>.  The effect is, that (<statement> ...  ) is executed and
afterwards the following statements are executed.
.\"}}}
.\"{{{  deffun
.LP
(deffun <name> (<statement> ... ) )
.SP
The operations in (<statement> ... ) are written to the .origamirc-file
so that origami can initialize a fix-macro-buffer.  Recursion is
allowed. You can use <name> in the following OCL-text as subroutine-calls
or for keybinds.  You cannot redefine the fix-macro-buffer.
.\"}}}
.\"{{{  initmac
.LP
(initfun <name> (<statement> ... ) )
.SP
Same as above.  But the macro can be redefined with ``O_DEFINE_FIX''.
Using the commands `defmac' and `initmac' uses the fix-macro-buffers
64,63, etc.
.\"}}}
.\"{{{  forward
.LP
(forward <name>)
.SP
<name> is declared as a name for a macro defined with ``initfun'' or
``deffun''.  <name> can be used from now on as normal macro-call.  The
definition with ``(deffun <name> ...  '' can be put somewhere in the
following script.
.\"}}}
.\"{{{  automacro
.LP
(automacro <name>)
.SP
If Origami is invoked using the ``\-A'' flag,
the macro named <name> is called every time you are exiting a filed fold,
entering it or opening a new file.
.\"}}}
.LP
Warning:
Using ``O_DEFINE_FIX x'' has no effect on macros defined with
``initfun'' or ``defmac'' when calling them by their name.  If you want
to use such an effect you must use ``O_CALL_FIX x''.
.\"}}}
.\"{{{  control structures
.NH 3
Control structures
.LP
A <statement> can be one of the following control structures or functions:
.\"{{{  while
.LP
while <condition> (<statement> ... )
.SP
Prechecked loop, the macro is repeated while the condition is true.
.\"}}}
.\"{{{  do while
.LP
do (<stament> ... ) while <condition>
.SP
Postchecked loop, the macro is repeated until the condition is false.
.\"}}}
.\"{{{  if else fi
.LP
if <condition> (<statement> ... ) fi
.br
if <condition> (<statement> ... ) else (<statement> ... ) fi
.SP
Conditional statement.  If condition is true, the first macro is
executed.  If condition is false, the second macro, if any, is executed.
.\"}}}
.\"{{{  case esac
.LP
case (<condition> (<statement> ... )) ... esac
.br
case (<condition> (<statement> ... )) ... default (<statement> ... ) esac
.SP
Conditional statement.  The block of statements following the first
conditional expression evaluating to TRUE is executed.  If no condition
is true, the given default-statements are executed.
.\"}}}
.\"{{{  repeat
.LP
repeat <number> (<statement> ... )
.SP
(<statement> ... ) is repeated <number> times.
.br
ATTENTION: The tokens are stored <number> times!.  This cannot be done
in another way, because origami knows no local variables!.  If you want
to repeat big macros, think about an implementation with counters.
.\"}}}
.\"{{{  prompt
.LP
prompt <prompt>
.SP
Displays <prompt> below the statusline.  <prompt> can be:
.DS
<string>
(<prompt-item> ...  )
.DE
where <prompt-item> can be:
.DS
counter <name>
<string>
.DE
Origami displays the ``prompt'' and waits till you type a ``O_RETURN''
on your keyboard.
.\"}}}
.\"{{{  exits
.LP
exit
.SP
The macroexecution is aborted.  Origami waits for keyboardinput.
.LP
message-exit <prompt>
.SP
Same as exit.  <prompt> is displayed under the statusline.
.\"}}}
.\"{{{  return-from-macro
.LP
return-from-macro
.SP
The currently executed macro ends and the caller (keyboard or macro)
continues again.
.\"}}}
.\"{{{  local
.LP
local (<name> ... ) (<statement> ...)
.SP
The values of the variables <name> ...  are saved during the execution
of ``<statement> ...''.  After the execution of the ``local''-statement
all saved variables are reset to their original values.
.br
ATTENTION: ``<statement> ...'' is executed as a subroutine, so using
``return-from-macro'' inside ``<statement> ...'' will only leave
``<statement> ...'', and not the current macro.
.\"}}}
.\"{{{  origami-commands
.LP
<origami-command>
.SP
All Origami commands you can use from keyboard can be used by their names.
.\"}}}
.\"{{{  strings
.LP
<strings>
.SP
Normal text can be used. The syntax is:
.DS
"text
where text can be a any string not containing: <space> " )
"<space> for <space>
") for )
"" for "
.DE
.LP
Warning: if you use origami to edit a OCL-file: "<space> should not
be the last statement of a line, because origami deletes all spaces at
end of line. If you put a comment after the "<space> command you have
no problems.
.\"}}}
.\"}}}
.\"{{{  variables
.NH 3
Variables
.LP
OCL allows to use variables.  OCL variables are global integer
variables.  They are declared by using them.  They are initialized to
zero when Origami starts up.  The following functions deal with
variables and can be used in the same way like the above mentioned
statements:
.\"{{{  set-counter
.LP
set-counter <name> <number>
.SP
The counter-variable <name> is set to the value of <number>.
.\"}}}
.\"{{{  prompt-counter
.LP
prompt-counter <name> <prompt>
.SP
Prompts <string> below the statusline and reads the new value for <name>
from keyboard.  Input ``y'' sets it to 1, ``n'' sets it to 0.  All other
inputs have to be decimals or a simple O_RETURN.  <prompt> is explained
in section ``Control structures''.
.\"}}}
.\"{{{  read-repeat
.LP
read-repeat <name>
.SP
The counter-variable <name> takes its value of the
``repeat-argument-counter''.  This counter is set to 0, so that the
macro-call is not repeated.  The value of ``repeat-macro-counter'' is
the number of remaining loops when using ``set-argument-x'', otherwise
0.
.\"}}}
.\"{{{  add-counter
.LP
add-counter <name> <number>
.SP
The counter-variable <name> is set to <name>+<number>.
.\"}}}
.\"{{{  sum-counter
.LP
sum-counter <name1> <name2>
.SP
The counter-variable <name1> is set to <name1>+<name2>.
.\"}}}
.\"{{{  inv-counter
.LP
inv-counter <name>
.SP
The counter-variable <name> is set to -<name>.
.\"}}}
.\"{{{  goto
.LP
goto <number>
.SP
Move the cursor on x-position <number>.  1 is the first displayed
character.  If you enter a indented fold, position 1 is not the
first character on that line.
.\"}}}
.\"{{{  goto-counter
.LP
goto-counter <name>
.SP
Same as above, except that the position is the value of variable <name>.
.\"}}}
.\"{{{  store-pos
.LP
store-pos <name>
.SP
The x-position of the cursor is stored in the variable <name>.
.\"}}}
.\"{{{  goto-line-counter
.LP
goto-line-counter <name>
.SP
Like O_GOTO_LINE.  The linenumber is the value of variable <name>.
.\"}}}
.\"{{{  store-line
.LP
store-line <name>
.SP
The current line-number is stored in the variable <name>.
.\"}}}
.\"{{{  counter
.LP
counter <name>
.SP
The current value of <name> is returned as ASCII-text.
.\"}}}
.\"}}}
.\"{{{  boolean expressions
.NH 3
Boolean expressions
.LP
The above mentioned boolean expressions <condition> can be:
.\"{{{  boolean operators
.\"{{{  not
.LP
not(<condition>)
.SP
The value of <condition> is inverted.
.\"}}}
.\"{{{  and
.LP
and(<condition>,<condition>)
.SP
is true, if both <condition>'s are true.
.\"}}}
.\"{{{  or
.LP
or(<condition>,<condition>)
.SP
is true, if one of the <condition>'s is true.
.\"}}}
.\"{{{  pre
.LP
pre (<statement> ... ) <condition>
.SP
The sequence of statements will be executed before the evaluation of
<condition>.
.\"}}}
.\"}}}
.\"{{{  boolean basicfunctions
.\"{{{  test-file-changed
.LP
test-file-changed
.SP
is true, if the current file has been changed.
.\"}}}
.\"{{{  test-filed
.LP
test-filed
.SP
is true if the current line is a file-folded-line.
.\"}}}
.\"{{{  test-fold-line
.LP
test-fold-line
.SP
is true if the current line is a closed-fold-line.
.\"}}}
.\"{{{  test-begin-fold
.LP
test-begin-fold
.SP
is true if the current line is the {\&{\&{ line of a open fold.
.\"}}}
.\"{{{  test-end-fold
.LP
test-end-fold
.SP
is true if the current line is the }\&}\&} line of a open fold
.\"}}}
.\"{{{  test-text
.LP
test-text
.SP
is true if the current line is a normal text-line.
.\"}}}
.\"{{{  test-top
.LP
test-top
.SP
is true if the current line is the top of the entered fold.
.\"}}}
.\"{{{  test-bottom
.LP
test-bottom
.SP
is true if the current line is the bottom of the entered fold.
.\"}}}
.\"{{{  test-char
.LP
test-char "x
.SP
is true if the character under the cursor is equal to x.
.\"}}}
.\"{{{  test-language
.LP
test-language "x
.SP
is true if x is the language used by ``set-language''.
.\"}}}
.\"{{{  counter-0
.LP
counter-0 <name>
.SP
is true if the variable <name> is 0.
.\"}}}
.\"{{{  counter>0
.LP
counter>0 <name>
.SP
is true if the variable <name> is greater than 0.
.\"}}}
.\"{{{  test-begin-line
.LP
test-begin-line
.SP
is true if the cursor stands on or before the first non-space-character
of the current line.
.\"}}}
.\"{{{  test-end-line
.LP
test-end-line
.SP
is true if the cursor stand behind the last non-space-character of the
current line.
.\"}}}
.\"{{{  test-behind-counter
.LP
test-behind-counter
.SP
is true if the position in line is after the value of the counter-
variable.
.\"}}}
.\"}}}
.\"{{{  comments
.LP
OCL uses short-circuit evaluation for ``and'' and ``or''.  Boolean
expressions can be used everywhere in the code.  When ``Origami'' is
prompting for information (for example, if a existing file should be
overwriten during O_FILE_FOLD), you can only use ``and'', ``or'',
``not'' and the following basic-expressions:
.DS
test-file-changed
test-language
test-text
test-begin-fold
test-fold-line
test-end-fold
test-filed
test-counter-0
test-counter>0
.DE
.\"}}}
.\"}}}
.\"{{{  multiple keyboards
.NH 3
Multiple keyboardmodes
.LP
To create more complex keybindings (for example a ``vi''-emulation with
modes), OCL offers the possibility to use up to four different
keyboard-translation-tables.  To do this, you must declare the used
keytabs with:
.LP
(defmodes <name> ... )
.SP
where <name> is a normal string.  This command has two effects:
.IP \(bu 1.5c
Keybind initializes a keytable for each <name>.
.IP \(bu 1.5c
The macros <name> are defined and can be used within other
macrodefinitions to switch to a certain keytab.  They are not stores in
fixmacrobuffers, but you can use them for your one macrodefinitions.
.LP
The first mentioned mode is active when starting origami.  The definition
of a declared keyboard can be done with:
.LP
(mode <name> (keybind ... ) ... )
.SP
All given bindings are put into the keytable for <name>.
``(keybind abort ...  )'' must be declared outside
a ``(mode ...  )''-statement, which results in the fact
that you can only have one abort-key for all modes.
If using multiple keyboard modes, no other ``(keybind ...  )''-statement
is allowed outside ``(mode ...  )''-statements.
.\"}}}
.\"{{{  filed-folds
.NH 3
Handling of filed-folds
.LP
Using language ``NONE'', keybind will automatically include the contents
of filed-folds when reading the source-file.  Normally multiple
includes of the same file won't work , because redefining macros isn't
allowed.  To build a clean macro-library, you can use:
.\"{{{  nodup
.LP
nodup
.SP
The current file will only be read once even if you have another
filed-fold entry for this file.  This command makes it possible to have
macro-libraries like:
.DS
file1:
          :
     ...F helps
          :

file2:
          :
     ...F helps
          :

keyboard:
          :
     ...F file1
     ...F file2
          :
.DE
.\"}}}
.\"}}}
.\"}}}
.\"{{{  OCL examples
.NH 2
OCL examples
.LP
This section explains some useful OCL applications.  They are useful for
understanding OCL.  Perhaps you missed some functions while reading the
previous chapters.  Some of them are written in OCL and you will find
them here.  It is assumed that you are familiar with Origami before you
start writing in OCL.
.\"{{{  byebye
.NH 3
A first example
.LP
The first OCL example does not use any control structures.  It defines a
little macro named byebye.  You should play a little bit with such macros
for understanding how to compile them and for getting some syntax errors.
.DS
; this is an example for a macro-definition:
(deffun byebye
(
  O_BOT_OF_FOLD
  O_START_OF_LINE
  O_RETURN
  O_UP
  "end "  "of " "text
))
.sp
(keybind byebye (M-"x "bye))
.DE
byebye creates a new line containing `end of text' at the end of the
entered fold.
.\"}}}
.\"{{{  shell version control
.NH 3
Shell version control
.LP
Two more little macros deal with SVC.  Note that the check-out macro is
only for personal use of SVC.  If you are working in a group, someone
else may have edited the file, which will not change your own read-only
copy.  The advantage is that you can visit a file and decide if you want
to change it.
.DS
(deffun check-out (
  delete-mode-view
  shell-command "co "  "-l "  "$ORIFILE
))

(deffun check-in (
  save-file
  add-mode-view
  shell-command "ci "  "-u "  "$ORIFILE
))
.DE
.\"}}}
.\"{{{  mtool-top
.NH 3
MTool-version of O_TOP_OF_FOLD
.LP
This a macro-version of the command O_TOP_OF_FOLD as it is used in the
mtool-system.  The cursor moves to the begin of the currently opened
fold.
.DS
; example for a more complex macro
(deffun mtool-top
  (
    if test-end-fold (O_UP) fi
    while and(not(test-begin-fold),not(test-top)) (
      if test-end-fold (mtool-top) fi
      O_UP
    )
  )
)
.DE
While the cursor is not being located on top of a fold (entered or
opened) the cursor is moved up. If the macro finds the end-of-fold line
from another opened fold, this fold is skipped by a recursive call of
mtool-top.
.\"}}}
.\"{{{  fill-paragraph
.NH 3
Fill paragraph
.LP
The following example is an advanced macro.  It is too long for printing
it here, but it is included in the file fill-paragraph.
.PP
fill-paragraph fills all lines from cursor position to the next line
with a blank or a dot in the first column.  An end of a fold stops
filling too.  The first column of a line is here the first character in
currently entered fold, not opened fold!  Filling a line means to add
words from the next line if it is too short or to put words to the next
line if it is too long.  The default right margin is set to column 72.
If there are unfillable lines, fill-paragraph stops filling and
complains.
.LP
The filling can be done in the following 3 ways:
.IP "roff-mode (switched on when origami starts)" .75c
All ``. '' are expanded to ``.  ''.
.IP "block-mode" .75c
All `` '' are expanded to ``  '', till the line reaches the fill-margin.
.IP "ragged-mode" .75c
All ``  '' are replaced bye `` ''.
.nr PP .75v
.LP
The macro inv-blank-handle switches between these modes.
.LP
The macro set-fill-column allows to change to right margin.  To do so,
you can either use a numeric argument or put the cursor to the position of
the new right margin or put it to the left and wait for Origami asking
you about the new column width.
.\"}}}
.\"{{{  goto-matching-fence
.NH 3
Goto matching fence
.LP
If you are writing programs, you often want to know which closing paren
in a complicated expression fits to another opening paren.
goto-matching-fence performs this function.  It uses the character
under the cursor to determine if you are looking for a paren, a bracket or
a { and if you want to jump to the opening or the closing one.  If the
cursor stands somewhere in usual text, nothing will happen.  Hereafter
the macro searches the matching fence.  If it can't find it, it will
jump back to your old position.  If necessary, this macro opens and
closes folds.  Do not worry if it does not seem to stop searching.  If
your text is very long and there is no fitting fence, you will be
amazed how many folds you are using and how fast they can be opened and
closed, but usually goto-matching-fence goes back to your old position.
.\"}}}
.\"{{{  towers-of-hanoi
.NH 3
The towers of hanoi
.LP
This is a funny macro to demonstrate the power of OCL.  You should type a
string of a few characters without blanks, then start this macro and
have fun.  Warning: If you type more than about eight to ten characters, the
game will require a long time.
.\"}}}
.PP
I am sure that you will invent more useful OCL macros.  If you wrote a
really new and good one, please post it to the USENET newsgroup
comp.editors.
.\"}}}
