Lugaru's Epsilon
Programmer's
Editor 14.00

Context:
Epsilon User's Manual and Reference
   Primitives and EEL Subroutines
      . . .
      Operating System Primitives
         System Primitives
         Window System Primitives
         Timing
         Calling Windows DLLs
         Running a Process
      Control Primitives
         Control Flow
         Character Types
         Examining Strings
         . . .
      Input Primitives
         Keys
         The Mouse
         Window Events
         . . .
         Binding Primitives
      . . .

Previous   Up    Next
Other Process Primitives  Primitives and EEL Subroutines   Character Types


Epsilon User's Manual and Reference > Primitives and EEL Subroutines > Control Primitives >

Control Flow

error(char *format, ...)
when_aborting()       /* control.e */
quick_abort()

Epsilon provides several primitives for altering the flow of control from one statement to the next. The error( ) primitive takes arguments like say( ), displays the string as say( ) does, and then aborts the current command, returning to the main loop (see The Main Loop). In addition this primitive discards any type-ahead and calls the user-defined subroutine when_aborting( ) if it exists. The standard version of when_aborting( ) optionally rings the bell and removes the erroneous command from any keyboard macro being defined. The primitive quick_abort( ) acts like error( ) but displays no message.

user char user_abort;
int abort_key;
check_abort()

The variable user_abort is normally 0. It is set to 1 when you press the key whose value is abort_key. To disable the abort key, set abort_key to -1. By default, the abort_key variable is set to Control-G. Use the set-abort-key command to set the abort_key variable. See Interrupting a Command.

The primitive check_abort( ) calls error( ) with the argument "Canceled." if the variable user_abort is nonzero. Use the primitive check_abort( ) whenever a command can be safely aborted, since otherwise an abort will only happen when the command returns. Epsilon calls check_abort( ) internally during any searching operation (see Searching Primitives), when you use the delay( ) primitive (described below) to wait, or (optionally) during certain file matching primitives (see Listing Commands & Buffers & Files) and file input/output (see File Reading Primitives).

leave(?int exitcode)
when_exiting()              /* EEL subroutine */

The primitive leave( ) exits Epsilon with the specified exit code (or 0 if omitted). A nonzero exit code keeps Epsilon from saving any settings it normally would, such as the currently selected font's name, or the sizes of any resized dialogs.

Just before calling leave( ), Epsilon's standard commands call any subroutine whose name starts with do_when_exiting_. It receives one integer parameter, nonzero if the user said to exit without checking for unsaved buffers or saving the session. It should return no result. (It can abort if it needs to prevent Epsilon from exiting; it should never do this if its parameter was nonzero, though.) Epsilon also calls the when_exiting( ) subroutine; modifying it was an earlier way to customize Epsilon's behavior when exiting.

delay(int hundredths, int condition, ?int buf)

The delay( ) primitive takes an argument specifying a period of time, in hundredths of a second, and a bit pattern specifying additional conditions (with codes specified in codes.h). It waits until one of the conditions occurs, or until the specified time limit is reached. A time limit of -1 means to wait forever.

The condition code COND_KEY makes Epsilon return when a key is pressed or any key-generating input event occurs (like a mouse event, or getting the focus). The condition code COND_TRUE_KEY is similar, but only returns on actual keys, not mouse events or other events. The condition code COND_PROC makes Epsilon return when a concurrent process is waiting for input, or has exited. The condition code COND_PROC_EXIT makes Epsilon return when a concurrent process has exited. For the last two conditions, Epsilon checks on the buffer specified by the optional parameter buf. If buf is missing or zero, it checks the buffer named "process". These conditions are ignored if no process is running in the specified buffer.

The condition flag COND_RETURN_ABORT, in combination with COND_KEY, makes the delay( ) primitive return if the user presses the abort key, instead of aborting by calling the check_abort( ) primitive. (Note that if you don't specify COND_KEY or COND_TRUE_KEY as well, the primitive ignores all keys, including the abort key.)

This function varies a bit from one operating system to another. For example, the Unix version of Epsilon can't detect when a process is currently waiting for input, so it can only return when a process exits. Also see the timing functions in Timing.

int do_recursion()
leave_recursion(int val)
int recursive_edit() /* control.e */
int recursive_edit_preserve() /* control.e */
char _recursion_level;

The do_recursion( ) primitive starts a new loop for getting characters and interpreting them as commands. A recursive edit preserves the current values of the variables has_arg, iter, this_cmd, and prev_cmd, but does not preserve the current buffer, window, or anything else. (See The Main Loop.) Exit the recursion by calling the leave_recursion( ) primitive. It arranges for the main loop to exit, instead of waiting for another key to be executed. The call to do_recursion() will then return with a value of val, the argument of the call to leave_recursion( ).

Sometimes a recursive edit is done "secretly," and the user doesn't know that one is being used. For example, when Epsilon reads the name of a file using completion, it's actually doing a recursive edit. Keys like <Space> exit the recursive edit with a special code, and the function that did the recursive edit displays a menu, or whatever is needed, and then does another recursive edit.

Other times (typing Ctrl-r in query-replace, for example), the user is supposed to exit the recursive edit explicitly using the exit-level command. When you're supposed to use exit-level to exit, Epsilon displays extra [ ]'s in the mode line as a reminder. The recursive_edit( ) subroutine does a recursive edit, and arranges for these [ ]'s to appear by modifying the _recursion_level variable. It contains the number of extra [ ]'s to display. The recursive_edit( ) subroutine returns the value returned by do_recursion( ).

The recursive_edit_preserve( ) subroutine calls recursive_edit( ). If the user changes the current buffer or window during the recursion, recursive_edit_preserve( ) returns to the original buffer or window before itself returning. If the user deleted the original buffer or window during the recursive edit, this subroutine remains in the new buffer or window and returns 0. It returns 1 otherwise.

If you call leave_recursion( ) when there has been no matching do_recursion( ), Epsilon automatically invokes the command exit. If exit returns instead of calling the primitive leave( ), Epsilon begins its main loop again.

int setjmp(jmp_buf *location)
longjmp(jmp_buf *location, int value)

Epsilon implements aborting by two special primitives that allow jumping from a function to another point in that function or any of the functions that called it. The setjmp( ) primitive marks the place to return, storing the location in a variable declared like this:

jmp_buf location;

After calling setjmp( ) with a pointer to this structure, you can return to this place in the code at any time until this function returns by calling the longjmp( ) primitive. The first argument is a pointer to the same structure, and the second argument may be any nonzero value.

The first time setjmp( ) is called, it returns a zero value. Each time longjmp( ) is called, Epsilon acts as if it is returning from the original setjmp( ) call again, returning the second argument from the longjmp( ). For example:

one()
{
jmp_buf location;

if (setjmp(&location)){
        stuff("Back in one\n");
        return;
} else
        stuff("Ready to go\n");
two(&location);
}

two(loc)
jmp_buf *loc;
{
stuff("In two\n");
longjmp(loc, 1);
stuff("Never get here\n");
}

This example inserts the lines

Ready to go
In two
Back in one


jmp_buf *top_level;

The error( ) primitive uses the jump buffer pointed to by the top_level variable. If you wish to get control when the user presses the abort key, temporarily change the value of top_level to refer to another jump buffer. Make sure you restore it, however, or subsequent aborting may not work.



Previous   Up    Next
Other Process Primitives  Primitives and EEL Subroutines   Character Types


Lugaru Epsilon Programmer's Editor 14.00 manual. Copyright (C) 1984, 2020 by Lugaru Software Ltd. All rights reserved.