If I install a new hook I want to be able to chain the current hook to my hook. I can figure out how to do that, but what I'm unsure about is what to do about the opposite situation. What if somebody installs their own hook that chains my hook to theirs? If my program runs the next time, then it would see a foreign hook and attempt to chain itself to that and there would be a never ending cycle of the 2 hooks going back and forth every time the program runs.

So I'm wondering, what is good practice for chaining hooks together?
So obviously, (just for posterity) the way you chain hooks is that you first back up a current hook's address and page when you install your hook. In your hook, you can either choose to act on the input data, or, where you would normally leave the hook and give control back to the TI-OS, you instead swap pages to the previous hook's page, then call into it. You of course need to reset the page when you return and pass along whatever it does. And needless to say, this hook-swapping code would have to be somewhere outside of $4000 to $8000, specifically, somewhere in RAM.

As for being the one chained, you can easily detect that by checking the RAM location for your type of hook. For example, if your hook is a GetCSCHook, the following code would determine whether this hook is the current base GetCSCHook or has been chained through another hook (fyi, the base RAM location for a GetCSCHook is $9B88):


Code:
GetCSCHookAddress .equ $9B88
MyGetCSCHook:
    .db $83
    ;(code)
    call IsThisGetCSCBaseHook
    call nz,WeAreChained
    ;(more code)
    ret
IsThisGetCSCBaseHook:
    ld hl,GetCSCHookAddress
    ld b,(hl)
    in a,(6)
    cp b
    ret nz
    inc hl
    ld a,(hl)   ;next 4 lines are essentially bcall(_ldhlind)
    inc hl
    ld h,(hl)
    ld l,a
    ld de,MyGetCSCHook
    bcall(_cphlde)
    ret   ;nz set if not the same, z set if the same


Usual disclaimer: just made this up on the spot, I think it works.
Your hook is responsible for itself and only itself. If you're implementing hook chaining so that you can combine someone else's hook(s) and yours, it's your responsibility to deal with hook chaining.

It's very dependent on each of the 24 individual hooks -- they all have certain situations that can and can't be canceled, and that can influence the flow of the chain. Hook chaining is certainly not easy and it should only be used in certain situations, unless you're intending to write a hook manager, in which case I would direct you to http://brandonw.net/svn/calcstuff/HookMan/trunk/ which was an attempt to do just that.

EDIT: This chaining stuff should only happen during INSTALLATION of the hooks. Unless you're installing a hook that does nothing but execute all the hooks in the chain, a hook shouldn't have any code that explicitly deals with chaining.
BrandonW wrote:
EDIT: This chaining stuff should only happen during INSTALLATION of the hooks. Unless you're installing a hook that does nothing but execute all the hooks in the chain, a hook shouldn't have any code that explicitly deals with chaining.
Definitely agree on code that sets up a chain inside the hook, but what about code to check if we're chained inside the hook? Wouldn't there be no other place for such code?
Logically you shouldn't be doing this. A hook that executes other hooks in a chain should be copying the hook block back into RAM so that when the hook checks that area of memory, it'll always see itself. A "sub-hook" should never have to deal with the situation that it might not be currently installed and is being executed from some hook manager, the reason being that none of the existing hooks do that either.

Take TI's FLASH applications for example, they will check the hook blocks sometimes to make sure that all the necessary hooks for a particular function are installed first. What you're proposing would break all that.
One think I'm still not sure about, where do you actually store the old hook address? You can't embed it into the app so would it be in RAM somewhere?

I think I'll just overwrite existing hooks for now until I figure out how this works in better detail. Maybe the hook manager code will help me understand it better.
The logical place to put chaining information is an AppVar in RAM, since whatever hooks are in place will be wiped out on RAM clear, at which point your chaining information becomes invalid anyway.
The problem with that is that it's infeasible. Looking up the AppVar every time the hook fires takes far too long (at least for some hooks, like the cursor hook).

Hook managers aren't easy...that's why we still don't have a complete one...
BrandonW wrote:
The problem with that is that it's infeasible. Looking up the AppVar every time the hook fires takes far too long (at least for some hooks, like the cursor hook).[...]
Couldn't you do something extra-awkward by finding a place that's very unlikely to change, like the bottom of the stack? You could put the address at the bottom of the stack +0 +1, then the page at +2, and some watchdog value at +3. If your watchdog is not the expected value, you know the stack reached the unlikely condition of taking its full space, in which case it's likely that the calc is going to crash anyway.

I know this is a terrible idea in terms of "correctness" and especially in terms of portability, just a random thought for a quick-and-dirty hack.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement