home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 550b.lha / newser_v2.10 / iopatch.asm < prev    next >
Assembly Source File  |  1991-09-08  |  23KB  |  975 lines

  1. *****************************************************************************
  2. * Program:  IOpatch.asm - ©1990,91 by Dan Babcock
  3. * Function: This program patches the exec OpenDevice call, and allows the
  4. *           user to select a serial or parallel unit.
  5. *
  6. * Author:   Dan Babcock
  7. * History:  02/07/90 DB V0.50 Created
  8. *           09/22/90 DB V0.51 Added code to prevent redundant requesters
  9. *                             in certain cases.
  10. *           12/10/90 JL V0.52 Added code to parse the command line, and
  11. *                             allow various arguments (outlined below).
  12. *           01/12/91 DB V1.10 Misc. enhancements
  13. *           06/19/91 DB V1.20 Added CacheClearU call, changed gadget text
  14. *****************************************************************************
  15. * Program:  SelectWindow - ©1990 by The Puzzle Factory
  16. * Function: Get the users preference for which unit to open.
  17. *
  18. * Author:   Jeff Lavin
  19. * History:  01/29/90 JL V0.50 Created
  20. *           02/07/90 DB V0.51 Modified to include an "Internal" gadget.
  21. *           08/22/90 JL V0.52 Added borders to the gadgets.
  22. *                             Converted to Macro68 & new syntax.
  23. *           09/12/90 JL V0.53 Dynamically size everything now.
  24. *           09/26/90 JL V0.54 Fixed lores display problem.
  25. *           11/16/90 JL V0.55 Rearrainged gadgets; Gadget 0 is now full width.
  26. *
  27. * [To all: Please don't forget to bump the revision numbers if you do *any*
  28. *          modifications at all.  -Jeff]
  29. *****************************************************************************
  30.  
  31.  
  32. *****************************************************************************
  33. * NAME
  34. *     IOpatch - This program patches the exec OpenDevice call. The user
  35. *     puts this program in his startup-sequence or whereever before he runs
  36. *     his terminal progs, BBS's and whatnot - if these do not permit the
  37. *     user to change the device/unit info. If they do, this utility is not
  38. *     needed, obviously.
  39. *
  40. * INPUTS
  41. *
  42. *     1> IOpatch       ;Check OpenDevice() calls for serial & parallel device
  43. *     1> IOpatch -a    ;Check OpenDevice() calls for serial & parallel device
  44. *     1> IOpatch -s    ;Check OpenDevice() calls for serial device only
  45. *     1> IOpatch -p    ;Check OpenDevice() calls for parallel device only
  46. *     1> IOpatch -q    ;Replaces previous vector for OpenDevice() calls.
  47. *     1> IOpatch ?     ;Prints these instructions
  48. *
  49. * RESULTS
  50. *     OpenDevice() will use the either:
  51. *
  52. *          the serial.device or the newser.device
  53. *          the parallel.device or the eightbit.device
  54. *
  55. *     with the proper unit number depending on which device was to have been
  56. *     opened, and what the user selected from the requester.
  57. *
  58. * NOTES
  59. *     There is one complication: I noticed during testing that most term
  60. *     programs open and close the serial.device several times during their
  61. *     startup routines. This is rather stupid of them, of course, and it
  62. *     unfortunately results in many redundant requesters.
  63. *     This version tries its best to avoid this problem by keeping track of
  64. *     tasks that have opened the serial/parallel device and re-using
  65. *     previously specified (by the user via the requester) unit number.
  66. *     One last note: this program copies itself into dynamically allocated
  67. *     memory, so the user does not have to "run" it.
  68. *     It does a CacheClearU if running under 2.0.
  69. ******************************* tear here ***********************************
  70.  
  71. ;Set Tabs           |       |                 |       |
  72.  
  73.     ifnd    __m68
  74.     fail    'Wrong assembler!'
  75.     endc
  76.     exeobj
  77.     macfile    'IOexp.i'    ;The One & Only include file
  78.     objfile    'IOpatch'
  79.  
  80. TASKTABLESIZE    equ    32
  81.  
  82. Dispatcher    moveq    #-1,d2    ;serflag default
  83.     moveq    #-1,d3    ;parflag default
  84.     moveq    #0,d6    ;quit flag default
  85.     moveq    #0,d5    ;Clear WBenchMsg
  86.  
  87.     movea.l    (SysBase).w,a6
  88.     movea.l    (ThisTask,a6),a2
  89.     tst.l    (pr_CLI,a2)    ;Are we a child of WBench?
  90.     bne.b    FromCLI    ;Branch if no
  91.  
  92.     lea    (pr_MsgPort,a2),a0
  93.     SYS    WaitPort
  94.     lea    (pr_MsgPort,a2),a0
  95.     SYS    GetMsg
  96.     move.l    d0,d5    ;WBenchMsg
  97.     bra.w    SetPatch    ;No args from WBench
  98.  
  99. FromCLI    lea    (a0,d0.w),a1
  100. ..    cmpi.b    #' ',-(a1)    ;Eat trailing garbage
  101.     dbhi    d0,..
  102.     blt.b    SetPatch    ;If no arguments, don't parse
  103.     clr.b    (1,a1)    ;Null terminate the string
  104.  
  105. Parse    moveq    #0,d0
  106.     move.b    (a0)+,d0
  107.     beq.b    SetPatch    ;Null ends
  108.     cmpi.b    #' ',d0    ;Skip spaces
  109.     beq.b    Parse
  110.     cmpi.b    #'?',d0    ;Instruct?
  111.     beq.b    4$    ;"Usage:..."
  112.     cmpi.b    #'-',d0    ;Look for "-" char
  113.     bne.b    Parse    ;Skip til we find one
  114.     move.b    (a0)+,d0    ;Get next char
  115.     beq.b    SetPatch    ;Null ends
  116.     cmpi.b    #'a',d0    ;Convert to U/C
  117.     blo.s    1$
  118.     cmpi.b    #'z',d0
  119.     bhi.s    1$
  120.     subi.b    #$20,d0
  121.  
  122. 1$    cmpi.b    #'A',d0    ;[A]ll
  123.     bne.b    2$
  124.     seq    d2    ;serflag
  125.     seq    d3    ;parflag
  126.     bra.b    SetPatch
  127.  
  128. 2$    cmpi.b    #'S',d0    ;[S]erial only
  129.     bne.b    3$
  130.     seq    d2    ;serflag
  131.     sne    d3    ;parflag
  132.     bra.b    SetPatch
  133.  
  134. 3$    cmpi.b    #'P',d0    ;[P]arallel only
  135.     bne.b    4$
  136.     sne    d2    ;serflag
  137.     seq    d3    ;parflag
  138.     bra.b    SetPatch
  139.  
  140. 4$    cmpi.b    #'Q',d0    ;[Q]uit
  141.     bne.w    Instruct
  142.     seq    d6    ;quit flag
  143.  
  144. ;Note that multitasking is disabled (via Forbid) throughout the install
  145. ;code for 100% safety.
  146. ;First, check to see whether this program has been run before.
  147.  
  148. SetPatch    lea    (serflag,pc),a0
  149.     move.b    d2,(a0)
  150.     lea    (parflag,pc),a0
  151.     move.b    d3,(a0)
  152.  
  153.     movea.l    (SysBase).w,a6
  154.     SYS    Forbid
  155.  
  156.     lea    (portname,pc),a1
  157.     SYS    FindPort
  158.     move.l    d0,d2
  159.     tst.l    d2
  160.     bne.b    installed    ;Go if already installed
  161.  
  162. ;Not installed, so allocate memory and copy
  163.  
  164.     move.l    #enddispatchcode-startdispatchcode,d7
  165.     move.l    d7,d0
  166.     moveq    #0,d1    ;No special attributes
  167.     SYS    AllocMem
  168.     tst.l    d0
  169.     bne.b    allocok
  170.  
  171. panic    tst.l    d5    ;WBenchMsg
  172.     beq.b    1$
  173.     movea.l    d5,a1    ;We're already forbidden
  174.     SYS    ReplyMsg    ;Return msg
  175.     bra.b    2$
  176.  
  177. 1$    SYS    Permit
  178. 2$    moveq    #-1,d0
  179.     rts
  180.  
  181. allocok    movea.l    d0,a5
  182.     movea.l    d0,a1
  183.     lea    (startdispatchcode,pc),a0
  184.     move.l    d7,d0
  185.     SYS    CopyMem
  186.     cmpi.w    #37,(LIB_VERSION,a6)    ;version 2.0?
  187.     blo.b    .SkipCache
  188.     moveq    #-1,d0
  189.     SYS    CacheClearU
  190. .SkipCache:
  191.     lea    (panic,pc),a4
  192.     jmp    (a5)    ;Go to startdispatchcode
  193.  
  194. installed    tst.b    d6    ;Go if already installed
  195.     beq.b    quitdispatch    ;& quit flag set
  196.  
  197. ;Remove the patch (port addr in d2)
  198.  
  199.     movea.l    d2,a2
  200.     movea.l    (MP_SIZE,a2),a3    ;Get start addr of res code
  201.     lea    (newopendevice-startdispatchcode,a3),a4 ;Get addr of replacement
  202.     cmpa.l    (_LVOOpenDevice+2,a6),a4 ;Still there?
  203.     bne.b    panic    ;No, so can't deinstall
  204.     lea    (newremtask-startdispatchcode,a3),a4 ;Get addr of replacement
  205.     cmpa.l    (_LVORemTask+2,a6),a4 ;Still there?
  206.     bne.b    panic    ;No, so can't deinstall
  207.  
  208.     move.l    (oldopenvec-startdispatchcode,a3),d0
  209.     movea.w    #_LVOOpenDevice,a0
  210.     movea.l    a6,a1
  211.     SYS    SetFunction
  212.  
  213.     move.l    (oldremtask-startdispatchcode,a3),d0
  214.     movea.w    #_LVORemTask,a0
  215.     movea.l    a6,a1
  216.     SYS    SetFunction
  217.  
  218.     movea.l    a2,a1    ;Deallocate memory etc.
  219.     SYS    RemPort
  220.  
  221.     moveq    #MP_SIZE+4,d0
  222.     movea.l    a2,a1
  223.     SYS    FreeMem    ;Free message port
  224.  
  225.     move.l    #enddispatchcode-startdispatchcode,d0
  226.     movea.l    a3,a1
  227.     SYS    FreeMem    ;Free the code
  228.  
  229. quitdispatch    tst.l    d5    ;WBenchMsg
  230.     beq.b    1$
  231.     movea.l    d5,a1    ;We're already forbidden
  232.     SYS    ReplyMsg    ;Return msg
  233.     bra.b    2$
  234.  
  235. 1$    SYS    Permit
  236. 2$    moveq    #0,d0
  237.     rts
  238.  
  239. Instruct    tst.l    d5    ;WBenchMsg
  240.     beq.b    .OpenDos
  241.     addq.b    #1,(TDNestCnt,a6)    ;Forbid so WBench won't
  242.     movea.l    d5,a1    ; UnloadSeg() us
  243.     SYS    ReplyMsg    ;Return msg
  244.     bra.b    .Exit
  245.  
  246. .OpenDos    lea    (DosName,pc),a1
  247.     moveq    #0,d0
  248.     SYS    OpenLibrary    ;Open dos.library
  249.     tst.l    d0
  250.     beq.b    .Exit    ;Failed!
  251.  
  252.     move.l    a6,-(sp)
  253.     movea.l    d0,a6
  254.     SYS    Output    ;Get output filehandle
  255.     move.l    d0,d1    ;Filehandle
  256.     beq.b    .CloseDos
  257.     lea    (Help.msg,pc),a0
  258.     move.l    a0,d2    ;Buffer
  259.     move.l    #Help_Len,d3    ;Length
  260.     SYS    Write    ;Help the user
  261.  
  262. .CloseDos    movea.l    a6,a1
  263.     movea.l    (sp)+,a6
  264.     SYS    CloseLibrary    ;Close the dos.library
  265. .Exit    moveq    #0,d0
  266.     rts
  267.  
  268.  
  269. ;***** All the following code is copied into dynamically allocated mem
  270.  
  271. ;Add a port to indicate that we're installed
  272. ;Allocate memory for the port
  273.  
  274. startdispatchcode    moveq    #MP_SIZE+4,d0    ;MsgPort+4 bytes of private info
  275.     moveq    #1,d1
  276.     swap    d1    ;CLEAR parm
  277.     SYS    AllocMem
  278.     tst.l    d0
  279.     bne.b    somememleft
  280.  
  281.     move.l    d7,d0    ;Uh oh. The poor user is out of memory.
  282.     move.l    a4,-(sp)    ;Return addr
  283.     movea.l    a5,a1
  284.     jmp    (_LVOFreeMem,a6)    ;RTS takes us back to 'panic'
  285.  
  286. somememleft    movea.l    d0,a1
  287.     lea    (portname,pc),a0
  288.     move.l    a0,(LN_NAME,a1) 
  289.     move.l    a5,(MP_SIZE,a1)    ;Private info - addr of res code 
  290.     SYS    AddPort
  291.  
  292.     movea.w    #_LVOOpenDevice,a0 ;Patch into OpenDevice
  293.     movea.l    a6,a1
  294.     lea    (newopendevice,pc),a2
  295.     move.l    a2,d0
  296.     SYS    SetFunction
  297.  
  298.     lea    (oldopenvec,pc),a0
  299.     move.l    d0,(a0)
  300.  
  301.     movea.w    #_LVORemTask,a0 ;Patch into RemTask
  302.     movea.l    a6,a1
  303.     lea    (newremtask,pc),a2
  304.     move.l    a2,d0
  305.     SYS    SetFunction
  306.     lea    (oldremtask,pc),a0
  307.     move.l    d0,(a0)
  308.  
  309.     tst.l    d5    ;WBenchMsg
  310.     beq.b    1$
  311.     movea.l    d5,a1    ;We're already forbidden
  312.     SYS    ReplyMsg    ;Return msg
  313.     bra.b    2$
  314.  
  315. 1$    SYS    Permit 
  316. 2$    moveq    #0,d0
  317.     rts
  318.  
  319.  
  320. ;*** NOTE: A zero TCB (in A1) indicates self removal !!!!
  321. ;(this little fact nearly drove me nuts during debugging!)
  322.  
  323. newremtask:
  324.     move.l    a1,d0
  325.     bne.b    .L2
  326.     move.l    a1,-(sp)
  327.     SYS    FindTask
  328.     movea.l    (sp)+,a1
  329. .L2    move.l    a1,-(sp)
  330.     SYS    Forbid
  331.     movea.l    (sp)+,a1
  332.  
  333.     moveq    #TASKTABLESIZE-1,d1
  334.     lea    (sertasklist,pc),a0
  335. ..    cmp.l    (a0)+,d0
  336.     addq.l    #2,a0
  337.     dbeq    d1,..
  338.     bne.b    .L1
  339.     clr.l    (-6,a0)
  340. .L1
  341.  
  342.     moveq    #TASKTABLESIZE-1,d1
  343.     lea    (partasklist,pc),a0
  344. ..    cmp.l    (a0)+,d0
  345.     addq.l    #2,a0
  346.     dbeq    d1,..
  347.     bne.b    .L3
  348.     clr.l    (-6,a0)
  349. .L3
  350.  
  351.     move.l    a1,-(sp)
  352.     SYS    Permit
  353.     movea.l    (sp)+,a1
  354.     movea.l    (oldremtask,pc),a0
  355.     jmp    (a0)
  356.  
  357. newopendevice    movem.l d6-d7/a2-a5,-(sp)
  358.     suba.l    a5,a5    ;Sanity check
  359.     tst.l    d0    ;Check unit number
  360.     bne    oldopenjump    ;If nonzero, skip menu
  361.     lea    (serunitexists,pc),a4
  362.     lea    (serflag,pc),a2
  363.     tst.b    (a2)+    ;Want to check serial device?
  364.     beq.b    1$    ;Branch if no
  365.     movea.l    a0,a3
  366. ..    cmpm.b    (a2)+,(a3)+
  367.     bne.b    1$
  368.     tst.b    (-1,a2)
  369.     bne.b    ..
  370.     lea    (newserialname,pc),a5
  371.     moveq    #0,d5
  372.     bra.b    2$
  373.  
  374. 1$    lea    (parflag,pc),a2
  375.     tst.b    (a2)+    ;Want to check parallel device?
  376.     beq.b    2$    ;Branch if no
  377.     movea.l    a0,a3
  378. ..    cmpm.b    (a2)+,(a3)+
  379.     bne.w    nogood
  380.     tst.b    (-1,a2)
  381.     bne.b    ..
  382.     lea    (newparallelname,pc),a5
  383.     moveq    #1,d5
  384.     addq.w    #4,a4    ;Point to parunitexists
  385.  
  386. ;One last check: if this task has previously opened either the serial.device
  387. ;or the parallel.device, use the same unit number (stored in tasklist) rather
  388. ;than bothering the user.
  389.  
  390. 2$    cmpa.l    #0,a5    ;Sanity check
  391.     beq    nogood    ;User has disabled both flags!
  392.  
  393.     movem.l    d0/d1/a0/a1,-(sp)
  394.     move.l    (ThisTask,a6),d6
  395.     SYS    Forbid
  396.     moveq    #15,d7
  397.     lea    (sertasklist,pc),a2
  398.     tst.l    d5
  399.     beq.b    .skippar
  400.     lea    (partasklist,pc),a2
  401. .skippar:
  402. ..    cmp.l    (a2)+,d6    
  403.     addq.l    #2,a2
  404.     dbeq    d7,..
  405.     bne.b    popup
  406.     SYS    Permit
  407.     movem.l    (sp)+,d0/d1/a0/a1
  408.     moveq    #0,d0
  409.     move.w    (-2,a2),d0
  410.     bra.b    skipmenu
  411.  
  412. popup    SYS    Permit
  413.     movem.l    (sp)+,d0/d1/a0/a1
  414.  
  415. ;pop up a menu
  416.  
  417.     move.l    (a4),d0    ;serunitexists/parunitexists
  418.     movem.l    d1-d7/a0-a6,-(sp)
  419.     bsr    SelWin    ;Get input from the user
  420.     movem.l    (sp)+,d1-d7/a0-a6
  421.     tst.l    d0    ;Ok?
  422.     bpl.b    contdisp
  423.  
  424. ;The user is out of memory; signal an error
  425.  
  426.     moveq    #-1,d0 
  427.     move.b    d0,(IO_ERROR,a1)    ;Set error in the IO Request
  428.     bra.b    endnewopen
  429.  
  430. contdisp:
  431.  
  432. ;store the TCB ptr and the unit# in tasklist for future use
  433.  
  434. ;search for an empty slot
  435.     movem.l    d0/d1/a0/a1,-(sp)
  436.     SYS    Forbid
  437.     lea    (sertasklist,pc),a2
  438.     tst.l    d5
  439.     beq.b    .skippar
  440.     lea    (partasklist,pc),a2
  441. .skippar:
  442.     moveq    #TASKTABLESIZE-1,d7
  443. ..    tst.l    (a2)+
  444.     addq.w    #2,a2
  445.     dbeq    d7,..
  446.     bne.b    oldtask    ;Full! (not likely to happen)
  447.     SYS    Permit
  448.     movem.l    (sp)+,d0/d1/a0/a1
  449.     move.l    d6,(-6,a2)
  450.     move.w    d0,(-2,a2)    
  451.     bra.b    skipmenu
  452. oldtask:
  453.     SYS    Permit
  454.     movem.l    (sp)+,d0/d1/a0/a1
  455.  
  456. skipmenu:
  457.     tst.l    d0
  458.     beq.b    oldopenjump    ;If zero, use std device
  459.     subq.l    #1,d0
  460.  
  461. oldtask1    movea.l    a5,a0    ;newserialname/newparallelname
  462. nogood 
  463. oldopenjump    movea.l    (oldopenvec,pc),a3
  464.     jsr    (a3)
  465. endnewopen    movem.l    (sp)+,d6-d7/a2-a5
  466.     rts
  467.  
  468. oldopenvec    dl    0 
  469. oldremtask    dl    0
  470.  
  471. ;These variables might be set by code that checks for the presence
  472. ;of units 3 and 4.  Right now, they're hard-coded to say that they exist.
  473. ;No harm is done if you select a non-existant unit, so it doesn't matter
  474. ;much.
  475.  
  476. serunitexists    dl    1
  477. parunitexists    dl    1
  478.  
  479. ;Note: TASKTABLESIZE entries, arranged like so:
  480. ;Ptr to TCB (longword)
  481. ;Unit number (word)
  482.  
  483. sertasklist:
  484.     dcb.l    TASKTABLESIZE,0
  485.     dcb.w    TASKTABLESIZE,0
  486. partasklist:
  487.     dcb.l    TASKTABLESIZE,0
  488.     dcb.w    TASKTABLESIZE,0
  489.  
  490. portname    cstr    'IOExp dispatcher V1.20 ©1990,91 by Dan Babcock *INSTALLED*'
  491. serflag    db    $FF    ;Default = ON
  492. oldserialname    cstr    'serial.device'
  493. newserialname    MYDEVNAME
  494. parflag    db    $FF    ;Default = ON
  495. oldparallelname    cstr    'parallel.device'
  496. newparallelname    PARDEVNAME
  497. DosName    cstr    'dos.library'
  498.  
  499. Help.msg    db    'I/O Expansion Dispatcher V1.20 ©1990,91 by Dan Babcock',10
  500.     db    'Usage:',10,10
  501.     db    ' IOpatch     ;Check OpenDevice() calls for serial & parallel device',10
  502.     db    ' IOpatch -a  ;Check OpenDevice() calls for serial & parallel device',10
  503.     db    ' IOpatch -s  ;Check OpenDevice() calls for serial device only',10
  504.     db    ' IOpatch -p  ;Check OpenDevice() calls for parallel device only',10
  505.     db    ' IOpatch -q  ;Replaces previous vector for OpenDevice() calls.',10
  506.     db    ' IOpatch ?   ;Prints these instructions',10,0
  507. Help_Len    equ    *-Help.msg
  508.     quad
  509.  
  510. *****************************************************************************
  511. * NAME
  512. *     SelectWindow - Get the users preference for which unit to open.
  513. *
  514. * SYNOPSIS
  515. *     SelectWindow (UnitExits)
  516. *          D0          D0
  517. *
  518. *     LONG  UnitExists;
  519. *
  520. * INPUTS
  521. *     UnitExists - Non-zero if units 2 and 3 exist, else 0.
  522. *
  523. * RESULTS
  524. *     A value of 0 if the user didn't select a unit and simply hit the close
  525. *     gadget (unit number then defaults to 0).
  526. *
  527. * -> A value of zero is also returned if the user selects the "Internal"
  528. * -> gadget, indicating that he wants to use "serial.device" rather than
  529. * -> "newser.device", or "parallel.device" rather than "eightbit.device".
  530. *
  531. *     A value of 1-4 is returned if the user has selected a unit.
  532. *     A return value of -1 indicates that an error has occured.
  533. *
  534. * NOTES
  535. *     SelectWindow is both relocatable, and reentrant.
  536. *     SelectWindow is Copyright ©1990 by The Puzzle Factory
  537. *
  538. ******************************* tear here ***********************************
  539.  
  540. MyFeatures    equ    SMART_REFRESH!NOCAREREFRESH!ACTIVATE
  541. MyGadgets    equ    WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
  542.  
  543. MyBase    clrso        ;BSS structure
  544. Gfx_Base    so.l    1
  545. Int_Base    so.l    1
  546. FontPtr    so.l    1
  547. ScreenPtr    so.l    1
  548. HiresFlag    so.b    1
  549. LaceFlag    so.b    1
  550. MyWindow    so.b    nw_SIZE
  551. Gadget0    so.b    gg_SIZEOF
  552. Gadget1    so.b    gg_SIZEOF
  553. Gadget2    so.b    gg_SIZEOF
  554. Gadget3    so.b    gg_SIZEOF
  555. Gadget4    so.b    gg_SIZEOF
  556.  
  557. Gad0.ITxt    so.b    it_SIZEOF
  558. Gad1.ITxt    so.b    it_SIZEOF
  559. Gad2.ITxt    so.b    it_SIZEOF
  560. Gad3.ITxt    so.b    it_SIZEOF
  561. Gad4.ITxt    so.b    it_SIZEOF
  562. MyBorder    so.b    bd_SIZEOF
  563. MyCoords    so.w    10
  564. Border0    so.b    bd_SIZEOF
  565. Coords0    so.w    10
  566. Text_Attr    so.b    ta_SIZEOF
  567. MB_Sizeof    soval
  568.  
  569. SelWin    move.l    d0,d3    ;UnitExists
  570.     moveq    #0,d7    ;Default = Nothing
  571.     move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  572.     move.l    #MB_Sizeof,d0
  573.     movea.l    (SysBase).w,a6
  574.     SYS    AllocMem
  575.     tst.l    d0
  576.     bne.b    1$
  577.     subq.l    #1,d0    ;Return -1 for error
  578.     rts
  579.  
  580. 1$    movea.l    d0,a5    ;Our relative base
  581.     lea    (GfxName,pc),a1    ;Open graphics.library
  582.     moveq    #33,d0
  583.  
  584.     SYS    OpenLibrary
  585.     move.l    d0,(Gfx_Base,a5)
  586.     beq    Error
  587.  
  588.     lea    (IntName,pc),a1    ;Open intuition.library
  589.     moveq    #33,d0
  590.     SYS    OpenLibrary
  591.     move.l    d0,(Int_Base,a5)
  592.     beq    Error
  593.     movea.l    d0,a6
  594.  
  595.     lea    (Text_Attr,a5),a1
  596.     lea    (FontName,pc),a0
  597.     move.l    a0,(ta_Name,a1)
  598.     move.w    #8,(ta_YSize,a1)
  599.     move.b    #FS_NORMAL,(ta_Style,a1)
  600.     move.b    #FPF_ROMFONT,(ta_Flags,a1)
  601.  
  602.     movea.l    (ib_ActiveScreen,a6),a0 ;Get active screen
  603.     move.l    a0,(ScreenPtr,a5)
  604.     move.w    (sc_Width,a0),d0
  605.     cmpi.w    #352,d0    ;Check horz resolution
  606.     sge    (HiresFlag,a5)
  607.     btst    #2,(sc_ViewPort+vp_Modes+1,a0)
  608.     sne    (LaceFlag,a5)
  609.  
  610.     lea    (MyBorder,a5),a1    ;Setup default border
  611.     lea    (Border0,a5),a2
  612.     clr.l    (a1)+    ;bd_LeftEdge,bd_TopEdge
  613.     clr.l    (a2)+    ;bd_LeftEdge,bd_TopEdge
  614.  
  615.     move.l    #$01000005,d0    ;bd_FrontPen,bd_BackPen,bd_DrawMode,bd_Count
  616.     move.l    d0,(a1)+
  617.     move.l    d0,(a2)+
  618.     lea    (MyCoords,a5),a0
  619.     move.l    a0,(a1)+    ;bd_XY
  620.     lea    (Coords0,a5),a0
  621.     move.l    a0,(a2)+    ;bd_XY
  622.  
  623.     lea    (Gadget0,a5),a4
  624.     lea    (Gad0.ITxt,a5),a3
  625.     lea    (GadText.tbl,pc),a2
  626.     tst.b    (HiresFlag,a5)
  627.     bne.b    3$
  628.     lea    (LoresText.tbl,pc),a2
  629. 3$    moveq    #0,d2
  630.  
  631. 4$    lea    (gg_SIZEOF,a4),a0
  632.     move.l    a0,(a4)+    ;gg_NextGadget
  633.  
  634.     moveq    #7,d0    ;0,1,3: LeftEdge=7
  635.     tst.w    d2    ;0
  636.     beq.b    5$
  637.     btst    #0,d2    ;Even or Odd?
  638.     bne.b    5$
  639.     moveq    #55,d0    ;2,4: LeftEdge=55
  640. 5$    tst.b    (HiresFlag,a5)
  641.     beq.b    6$
  642.     add.w    d0,d0
  643. 6$    move.w    d0,(a4)+    ;gg_LeftEdge
  644.  
  645.     moveq    #18,d0    ;0: TopEdge=18
  646.     tst.w    d2
  647.     beq.b    7$
  648.     addi.w    #22,d0    ;1,2: TopEdge=40
  649.     cmpi.w    #3,d2
  650.     blt.b    7$
  651.     addi.w    #22,d0    ;3,4: TopEdge=62
  652. 7$    tst.b    (LaceFlag,a5)
  653.     beq.b    8$
  654.     add.w    d0,d0
  655. 8$    move.w    d0,(a4)+    ;gg_TopEdge
  656.  
  657.     moveq    #40,d0    ;LORES
  658.     tst.w    d2    ;Gadget 0 only
  659.     bne.b    18$
  660.     addq.w    #4,d0
  661.     add.w    d0,d0
  662. 18$    tst.b    (HiresFlag,a5)
  663.     beq.b    9$
  664.     add.w    d0,d0    ;HIRES
  665. 9$    move.w    d0,(a4)+    ;gg_Width
  666.     lea    (MyCoords,a5),a0
  667.     tst.w    d2
  668.     bne.b    19$
  669.     lea    (Coords0,a5),a0    ;Gadget 0 only
  670. 19$    move.w    d0,(4,a0)    ;X border coords
  671.     move.w    d0,(8,a0)
  672.  
  673.     move.w    #18,d0    ;NORMAL
  674.     tst.b    (LaceFlag,a5)
  675.     beq.b    10$
  676.     add.w    d0,d0    ;LACE
  677. 10$    move.w    d0,(a4)+    ;gg_Height
  678.     lea    (MyCoords,a5),a0
  679.     tst.w    d2
  680.     bne.b    20$
  681.     lea    (Coords0,a5),a0    ;Gadget 0 only
  682. 20$    move.w    d0,(10,a0)    ;Y border coords
  683.     move.w    d0,(14,a0)
  684.  
  685.     move.w    #GADGHCOMP,(a4)+    ;gg_Flags
  686.     move.w    #GADGIMMEDIATE,(a4)+ ;gg_Activation
  687.     move.w    #BOOLGADGET,(a4)+    ;gg_GadgetType
  688.     lea    (MyBorder,a5),a0
  689.     tst.w    d2
  690.     bne.b    21$
  691.     lea    (Border0,a5),a0    ;Gadget 0 only
  692. 21$    move.l    a0,(a4)+    ;gg_GadgetRender
  693.     addq.w    #4,a4    ;gg_SelectRender
  694.     move.l    a3,(a4)+    ;gg_GadgetText
  695.     addq.w    #8,a4    ;gg_MutualExclude,gg_SpecialInfo
  696.     move.w    d2,(a4)+    ;gg_GadgetID
  697.     addq.w    #4,a4    ;gg_UserData
  698.  
  699.     move.l    #$01000000,(a3)+    ;it_FrontPen,it_BackPen,it_DrawMode
  700.  
  701.     moveq    #16,d0    ;Gad1-4/HIRES=16
  702.     tst.w    d2
  703.     bne.b    23$
  704.     tst.b    (HiresFlag,a5)    ;Gadget 0 only
  705.     beq.b    22$
  706.     moveq    #56,d0    ;Gad0/HIRES=56
  707.     bra.b    11$
  708.  
  709. 22$    moveq    #20,d0    ;Gad0/LORES=20
  710.     bra.b    11$
  711.  
  712. 23$    tst.b    (HiresFlag,a5)    ;Gadgets 1-4
  713.     bne.b    11$
  714.     subq.w    #4,d0    ;Gad1-4/LORES=12
  715. 11$    move.w    d0,(a3)+    ;it_LeftEdge
  716.  
  717.     moveq    #14,d0
  718.     tst.b    (LaceFlag,a5)
  719.     bne.b    12$
  720.     subq.w    #8,d0
  721. 12$    move.w    d0,(a3)+    ;it_TopEdge
  722.  
  723.     lea    (Text_Attr,a5),a0
  724.     move.l    a0,(a3)+    ;it_TextFont
  725.  
  726.     moveq    #0,d0
  727.     move.b    (a2)+,d0
  728.     move.l    a2,(a3)+    ;it_Text
  729.     add.l    d0,a2    ;Next text
  730.  
  731.     addq.w    #4,a3    ;it_NextText
  732.     addq.w    #1,d2    ;Next gadget
  733.     cmpi.w    #4,d2    ;All the gadgets done?
  734.     ble.w    4$
  735.  
  736.     clr.l    (Gadget4,a5)    ;gg_NextGadget
  737.  
  738.     lea    (Gadget0,a5),a0
  739.     ori.w    #SELECTED,(gg_Flags,a0)
  740.  
  741.     tst.l    d3    ;Units 2 & 3 exist?
  742.     bne.b    13$    ;Branch if yes
  743.     move.w    #GADGDISABLED,d0    ;Else, disable gadgets
  744.     lea    (Gadget3,a5),a0
  745.     or.w    d0,(gg_Flags,a0)
  746.  
  747.     lea    (Gadget4,a5),a0
  748.     or.w    d0,(gg_Flags,a0)
  749.  
  750. 13$    lea    (MyWindow,a5),a0
  751.     movea.l    (ScreenPtr,a5),a2 ;Get active screen
  752.     move.l    a2,(nw_Screen,a0)    ;
  753.  
  754.     move.w    #103,d0    ;LORES = 103
  755.     tst.b    (HiresFlag,a5)
  756.     beq.b    14$
  757.     add.w    d0,d0    ;HIRES = 206
  758. 14$    move.w    d0,(nw_Width,a0)
  759.     move.w    (sc_Width,a2),d1
  760.     lsr.w    #1,d1    ;Screen width / 2
  761.     lsr.w    #1,d0    ;Window width / 2
  762.     sub.w    d0,d1
  763.     move.w    d1,(a0)    ;nw_LeftEdge
  764.  
  765.     move.w    #88,d0    ;NORMAL = 88
  766.     tst.b    (LaceFlag,a5)
  767.     beq.b    15$
  768.     add.w    d0,d0    ;LACE = 176
  769. 15$    move.w    d0,(nw_Height,a0)
  770.     move.w    (sc_Height,a2),d1
  771.     lsr.w    #1,d1    ;Screen height / 2
  772.     lsr.w    #1,d0    ;Window height / 2
  773.     sub.w    d0,d1
  774.     move.w    d1,(nw_TopEdge,a0)
  775.  
  776.     move.b    #-1,(nw_DetailPen,a0)
  777.     move.b    #-1,(nw_BlockPen,a0)
  778.     move.l    #GADGETDOWN!CLOSEWINDOW,(nw_IDCMPFlags,a0)
  779.     move.l    #MyFeatures!MyGadgets,(nw_Flags,a0)
  780.     lea    (Gadget0,a5),a1
  781.     move.l    a1,(nw_FirstGadget,a0)
  782.     lea    (WindowTitle,pc),a1
  783.     tst.b    (HiresFlag,a5)
  784.     bne.b    16$
  785.     lea    (LoresTitle,pc),a1
  786. 16$    move.l    a1,(nw_Title,a0)
  787.     move.w    (sc_Flags,a2),d0
  788.     andi.w    #%00001111,d0
  789.     move.w    d0,(nw_Type,a0)
  790.     SYS    OpenWindow    ;Open window
  791.     movea.l    d0,a3    ;Save window pointer
  792.     tst.l    d0
  793.     beq.b    Error
  794.  
  795.     movea.l    (Gfx_Base,a5),a6
  796.     lea    (Text_Attr,pc),a0
  797.     SYS    OpenFont
  798.     move.l    d0,(FontPtr,a5)
  799.     beq.b    17$
  800.  
  801.     movea.l    d0,a0
  802.     movea.l    (wd_RPort,a3),a1
  803.     SYS    SetFont
  804.  
  805. 17$    moveq    #0,d6    ;Close flag
  806.     bsr.b    MainLoop
  807.     bra.b    Cleanup
  808.  
  809. ************************************************
  810. *             Termination section              *
  811. ************************************************
  812.  
  813. Error    subq.l    #1,d7
  814. Cleanup    move.l    (Gfx_Base,a5),d2
  815.     beq.b    2$
  816.     move.l    (FontPtr,a5),d0
  817.     beq.b    1$
  818.     movea.l    d0,a1
  819.     movea.l    d2,a6
  820.     SYS    CloseFont
  821.  
  822. 1$    movea.l    d2,a1
  823.     movea.l    (SysBase).w,a6
  824.     SYS    CloseLibrary
  825.  
  826. 2$    move.l    (Int_Base,a5),d2
  827.     beq.b    4$
  828.     move.l    a3,d0
  829.     beq.b    3$
  830.     movea.l d0,a0
  831.     movea.l    d2,a6
  832.     SYS    CloseWindow
  833.  
  834. 3$    movea.l    d2,a1
  835.     movea.l    (SysBase).w,a6
  836.     SYS    CloseLibrary
  837.  
  838. 4$    movea.l    a5,a1
  839.     move.l    #MB_Sizeof,d0
  840.     movea.l    (SysBase).w,a6
  841.     SYS    FreeMem
  842.     move.l    d7,d0    ;0-4, or -1 if error.
  843.     rts
  844.  
  845. ************************************************
  846. *             Main Execution Loop              *
  847. ************************************************
  848.  
  849. MainLoop    tst.w    d6    ;Flag set?
  850.     beq.b    1$
  851.     rts        ;Exit
  852.  
  853. 1$    movea.l (wd_UserPort,a3),a0
  854.     moveq    #0,d0
  855.     moveq    #0,d1
  856.     move.b    (MP_SIGBIT,a0),d1
  857.     bset    d1,d0
  858.     movea.l    (SysBase).w,a6
  859.     SYS    Wait    ;Now wait for a message
  860.  
  861. GetIMsg    movea.l (wd_UserPort,a3),a0
  862.     SYS    GetMsg
  863.     tst.l    d0
  864.     beq.b    MainLoop
  865.     movea.l d0,a1
  866.     move.l    (im_Class,a1),d2
  867.     movea.l    (im_IAddress,a1),a2
  868.     SYS    ReplyMsg
  869.  
  870.     cmpi.l    #CLOSEWINDOW,d2
  871.     bne.b    CheckGads
  872.     moveq    #-1,d6
  873.     bra.b    GetIMsg
  874.  
  875. CheckGads    cmpi.w    #GADGETDOWN,d2    ;Someone clicked on a gadget
  876.     bne.b    1$    ;Unknown class
  877.     moveq    #0,d7
  878.     move.w    (gg_GadgetID,a2),d7 ;ID = Unit number
  879.     lea    (Gadget0,a5),a1    ;1st gadget in group
  880.  
  881.     moveq    #5,d0    ;# of gadgets in group
  882.     bsr.b    MutualExclude
  883. 1$    bra.b    GetIMsg
  884.  
  885. *************************************************************************
  886. * NAME:     MutualExclude()
  887. * FUNCTION: Performs a MutualExclude function for Boolean gadgets.
  888. * INPUTS:   A3 = Window
  889. *           A2 = Currently selected gadget
  890. *           A1 = 1st gadget in group
  891. *           D0 = NumGads
  892. * RETURN:   None
  893. * SCRATCH:  D0-D1/A0-A1
  894. *************************************************************************
  895.  
  896. MutualExclude    move.l    a6,-(sp)
  897.     movea.l    (Int_Base,a5),a6
  898.     movem.l    d0/a1,-(sp)
  899.     movea.l    a3,a0    ;Window
  900.     SYS    RemoveGList
  901.     move.l    d0,d4    ;Position
  902.     movem.l    (sp),d1/a1
  903.     bra.b    3$
  904.  
  905. 1$    cmp.w    (gg_GadgetID,a1),d7 ;Is this the current gadget?
  906.     seq    d2    ;D2 = 1 if TRUE
  907.     btst    #7,(gg_Flags+1,a1)    ;Currently selected?
  908.     sne    d3    ;D3 = 1 if TRUE
  909.     eor.b    d2,d3
  910.     beq.b    2$
  911.     bchg    #7,(gg_Flags+1,a1)    ;Toggle the select flag
  912. 2$    movea.l    (a1),a1    ;gg_NextGadget
  913. 3$    dbra    d1,1$
  914.  
  915.     bsr.b    ClearScreen
  916.  
  917.     movea.l    a3,a0    ;Window
  918.     move.l    d4,d0    ;Position
  919.     movem.l    (sp),d1/a1    ;NumGads/Gadget
  920.     SYS    AddGList
  921.  
  922.     movea.l    a3,a1    ;Window
  923.     movem.l    (sp)+,d0/a0    ;NumGads/Gadget
  924.     SYS    RefreshGList
  925.     movea.l    (sp)+,a6
  926.     rts
  927.  
  928. ClearScreen    movem.l    a2/a6,-(sp)
  929.     movea.l    (Gfx_Base,a5),a6
  930.     movea.l    (wd_RPort,a3),a2
  931.     moveq    #0,d0
  932.     movea.l    a2,a1
  933.     SYS    SetAPen
  934.  
  935.     moveq    #4,d0    ;Xmin
  936.     moveq    #14,d1    ;Ymin
  937.     moveq    #0,d2
  938.     move.w    (wd_Width,a3),d2
  939.     subq.w    #4,d2    ;Xmax
  940.     moveq    #0,d3
  941.     move.w    (wd_Height,a3),d3
  942.     subq.w    #4,d3    ;Ymax
  943.     movea.l    a2,a1
  944.     SYS    RectFill
  945.  
  946.     moveq    #1,d0
  947.     movea.l    a2,a1
  948.     SYS    SetAPen
  949.     movem.l    (sp)+,a2/a6
  950.     rts
  951.  
  952. Notice    cstr    'SelectWindow ©1990 by The Puzzle Factory',10
  953. GfxName    cstr    'graphics.library'
  954. IntName    cstr    'intuition.library'
  955. FontName    cstr    'topaz.font'
  956. WindowTitle    cstr    'Select Unit:'
  957. LoresTitle    cstr    'Sel Unit:'
  958.  
  959. GadText.tbl:
  960.     cstr    9,'Internal'
  961.     cstr    7,'Unit 0'
  962.     cstr    7,'Unit 1'
  963.     cstr    7,'Unit 2'
  964.     cstr    7,'Unit 3'
  965.  
  966. LoresText.tbl:
  967.     cstr    9,'Internal'
  968.     cstr    3,'U0'
  969.     cstr    3,'U1'
  970.     cstr    3,'U2'
  971.     cstr    3,'U3'
  972.  
  973. enddispatchcode    end
  974.