#### 3.4.4.1 Command hooks ¶

In the previous section, we have seen how to extend `mixguile`’s functionality through the use of user defined functions. Frequently, you’ll write new functions that improve in some way the workings of a built-in `mixvm` command, following this pattern:

1. Prepare the command execution
2. Execute the desired command
3. Perform post execution operations

We call the functions executed in step (a) pre-hooks, and those of step post-hooks of the given command. `mixguile` lets you specify pre- and post-hooks for any `mixvm` command using the `mix-add-pre-hook` and `mix-add-post-hook` functions, which take as arguments a symbol naming the command and a function to be executed before (resp. after) the command. In other words, `mixguile` will execute for you steps (a) and (c) above whenever you eval (b). The hook functions must take a single argument, which is a string list of the command’s arguments. As an example, let us define the following hooks for the `next` command:

    (define next-pre-hook
      (lambda (arglist)
        (mix-slog #f)))

    (define next-post-hook
      (lambda (arglist)
        (display "Stopped at line ")
        (display (mix-src-line-no))
        (display ": ")
        (display (mix-src-line))
        (newline)
        (mix-slog #t)))

In these functions, we are using the function `mix-slog` to turn off the informational messages produced by the virtual machine, since we are providing our own ones in the post hook function. To install these hooks, we would write:

    (mix-add-pre-hook 'next next-pre-hook)
    (mix-add-post-hook 'next next-post-hook)

Assuming we have put the above expressions in `mixguile`’s initialisation file, we would obtain the following results when evaluating `mix-next`:

    guile> (mix-next)
    MIXAL HELLO WORLD
    Stopped at line 6:             HLT
    guile>

As a second, more elaborate, example, let’s define hooks which print the address and contents of a cell being modified using `smem`. The hook functions could be something like this:

    (define smem-pre-hook
      (lambda (arglist)
        (if (eq? (length arglist) 2)
            (begin
              (display "Changing address ")
              (display (car arglist))
              (newline)
              (display "Old contents: ")
              (display (mix-cell (string->number (car arglist))))
              (newline))
            (error "Wrong arguments" arglist))))

    (define smem-post-hook
      (lambda (arglist)
        (if (eq? (length arglist) 2)
            (begin
              (display "New contents: ")
              (display (mix-cell (string->number (car arglist))))
              (newline)))))

and we can install them using

    (mix-add-pre-hook 'smem smem-pre-hook)
    (mix-add-post-hook 'smem smem-post-hook)

Afterwards, a sample execution of `mix-smem` would look like this:

    guile> (mix-smem 2000 100)
    Changing address 2000
    Old contents: 0
    New contents: 100
    guile>

You can add any number of hooks to a given command. They will be executed in the same order as they are registered. You can also define global post (pre) hooks, which will be called before (after) any `mixvm` command is executed. Global hook functions must admit two arguments, namely, a string naming the invoked command and a string list of its arguments, and they are installed using the Scheme functions `mix-add-global-pre-hook` and `mix-add-global-post-hook`. A simple example of global hook would be:

    guile> (define pre-hook
             (lambda (cmd args)
               (display cmd)
               (display " invoked with arguments ")
               (display args)
               (newline)))
    guile> (mix-add-global-pre-hook pre-hook)
    ok
    guile> (mix-pmem 120 125)
    pmem invoked with arguments (120-125)
    0120: + 00 00 00 00 00 (0000000000)
    0121: + 00 00 00 00 00 (0000000000)
    0122: + 00 00 00 00 00 (0000000000)
    0123: + 00 00 00 00 00 (0000000000)
    0124: + 00 00 00 00 00 (0000000000)
    0125: + 00 00 00 00 00 (0000000000)
    guile>

Note that if you invoke `mixvm` commands within a global hook, its associated command hooks will be run. Thus, if you have installed both the `next` hooks described earlier and the global hook above, executing `mix-next` will yield the following result:

    guile> (mix-next 5)
    next invoked with arguments (5)
    slog invoked with arguments (off)
    MIXAL HELLO WORLD
    Stopped at line 7: MSG         ALF   "MIXAL"
    slog invoked with arguments (on)
    guile>

Adventurous readers may see the above global hook as the beginning of a command log utility or a macro recorder that saves your commands for replay.