/*------------------------------------------------------------------------*/
/****** misc/CheckSetPatchVersion ****************************************
*
*   NAME
*     CheckSetPatchVersion - Determine the system SetPatch level
*
*   SYNOPSIS
*       ok = CheckSetPatchVersion(SysBase, version, revision);
*
*       BOOL CheckSetPatchVersion(struct ExecBase *, UWORD, UWORD);
*
*   FUNCTION
*       Determines and checks if at least a required SetPatch is
*       installed. This is for software that wants to exploit
*       knowledge about installed bug fixes to avoid internal hacks
*       around OS bugs.
*
*   INPUTS
*     SysBase   - A pointer to ExecBase.
*
*     version   - The minimum acceptable version of SetPatch
*
*     revision  - The minimum acceptable revision of SetPatch
*
*   RESULT
*     ok        - This tells you if at least the patch you are looking
*                 for is installed.
*
*   EXAMPLE
*
*   NOTES
*       The result is valid until the system is rebooted. This function
*       will continue to work in a future OS if you heed the warnings.
*
*       Once a bug has been fixed in SetPatch, you can rest assured that
*       either a future OS or a future SetPatch will also contain that
*       bug fix. It is unlikely that fixed things are intentionally broken
*       again.
*
*       Obviously it is not enough to check the SetPatch version to see
*       if a bug is fixed. First you must make sure that you are using the
*       OS version that exhibits the bug to be fixed by SetPatch. Afterall
*       a SetPatch V43 can't e.g. fix V39 bugs on a V37 based Amiga.
*
*       DO NOT USE THIS FUNCTION TO SEE IF A BUG IS PRESENT! There is no
*       guarantee at all that any bug fix is not installed if this function
*       returns FALSE. Don't rely on side effects of any bug! This function
*       has been designed to tell you if known problems are fixed, not for
*       the contrary or any other interpretation of this description.
*
*       An 68K C compiler will generate less than 80 bytes for this also
*       ROMable function. There is little to be gained by recoding this in
*       assembler. You only lose portability completely.
*
*   SEE ALSO
*
******************************************************************************
*
*/
/*------------------------------------------------------------------------*/
/* Only ps_Version and ps_Revision may be accessed! Read only!
 * Do not try anything. This is off limits!
 */
struct SetPatchSemaphore
{
    struct SignalSemaphore  sps_Sem;        /* Don't touch! */
    struct MinList          sps_Private;    /* Don't touch! */
    UWORD                   sps_Version;    /* Version installed */
    UWORD                   sps_Revision;   /* Revision installed */
    /* Don't touch! */
};

/*------------------------------------------------------------------------*/
BOOL CheckSetPatchVersion(struct ExecBase *SysBase,
                          UWORD version, UWORD revision)
{
    struct SetPatchSemaphore *sem;
    BOOL foundsetpatch = FALSE;

    /* This may look strange, but it is ok.
     * An installed SetPatch will never be removed and once it
     * has been installed its version/revision won't change.
     * This is _guaranteed_!
     * So if the semaphore exists, it will never disappear again.
     * The result is that we can keep the Forbid (Yuck!) very short.
     * We pass in SysBase to be able to avoid any global/$4 access.
     */
    Forbid();
    sem = (struct SetPatchSemaphore *)FindSemaphore((STRPTR)"« SetPatch »");
    Permit();

    if(sem)
    {
        /* Do we have at least the requested version/revision? */
        if((version > sem->sps_Version) ||
           ((version == sem->sps_Version) && (revision >= sem->sps_Revision)))
        {
            /* Yes, we got it. The requested SetPatch has been installed */
            foundsetpatch = TRUE;
        } /* if */
    } /* if */

    return(foundsetpatch);

} /* CheckSetPatchVersion */


