home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / scrnsav2.asm < prev    next >
Assembly Source File  |  1988-09-01  |  27KB  |  735 lines

  1.         page    ,132
  2.         title   scrnsav2 : Screen Saver for PS/2
  3. ;
  4. ;  Copyright (c) 1988 Alan Ballard
  5. ;
  6. ;  This program is a TSR (Terminate and Stay Resident) utility
  7. ;  "screen saver".  It turns off the video after a specified period
  8. ;  of inactivity (no keyboard or mouse action).  Touching the keyboard or
  9. ;  the mouse will reactivate the screen.
  10. ;
  11. ;  A VGA monitor and the PS/2 extended bios are required.
  12. ;
  13. ;  The program stays resident only the first time it is run.  It may be reexecuted
  14. ;  to disable blanking or to change the interval.
  15. ;
  16. ;  Options are:
  17. ;    integer      - blanking time in minutes (default 5 minutes)
  18. ;    \d           - disable blanking
  19. ;    \e           - enable blanking (default)
  20. ;    \m integer   - set the "multiplex number" to use for communicating
  21. ;                   with the loaded version.
  22. ;
  23.  
  24. ;  Interrupt numbers
  25. Keyboard@ equ   09h
  26. Video_Io@ equ   10h
  27. System_Services@ equ 15h
  28. Timer@  equ     1ch
  29. Dos@    equ     21h
  30. Multiplex@ equ  2fh
  31. Mouse@  equ     74h
  32.  
  33. ; Video I/O function numbers
  34. Read_Display_Combination_Code equ 1a00h
  35.  
  36. ; System services function numbers
  37. Keyboard_Intercept equ 4fh
  38.  
  39. ; Multiplex function numbers
  40. Get_Installed_State equ 0
  41.  
  42. ; Scrnsav2 multiplex functions
  43. Scrnsav_Multiplex_Number equ 150       ; random choice
  44. Scrnsav_Disable equ     10h
  45. Scrnsav_Enable  equ     11h
  46. Scrnsav_Set_Interval equ 12h
  47.  
  48. ; DOS function numbers
  49. Print_String equ 09h
  50. Print_Char   equ 02h
  51. Set_Int equ     25h
  52. Get_Int equ     35h
  53. TSR     equ     31h
  54. Terminate equ   4ch
  55.  
  56. ; Miscellaneous constants
  57. Ticks_Per_Minute equ 1092               ; 60*18.2
  58. Default_Time equ 5                      ; five minute default
  59. Max_Time     equ 30                     ; 30 minute maximum (30*1092=32760)
  60.  
  61. Cr      equ     0dh
  62. Lf      equ     0ah
  63.  
  64. True    equ     0ffh
  65. False   equ     00h
  66.  
  67. ; VGA adaptor constants
  68. SAR     equ     03c4h                   ; Sequencer Address Register
  69. SDR     equ     03c5h                   ; Sequencer Data Register
  70. Clocking_Mode_Index equ 01              ; SAR index for clocking mode reg
  71. Screen_Mask equ 20h                     ; Mask for screen off bit.
  72.  
  73. Scrnsav2 segment para 'code'
  74.         assume  cs:Scrnsav2,ds:nothing,es:nothing
  75. ;
  76. ;  Overlay permanent data on PSP.
  77. ;
  78.         org     05ch                    ; not supposed to change anything before this
  79. Old_Mouse dd    ?                       ; save old int 74 (mouse)
  80. Old_Timer dd    ?                       ; save old timer tick
  81. Old_Ss    dd    ?                       ; save old system services
  82. Old_Multiplex dd ?                      ; save old multiplex
  83. ;
  84. Idle_Count dw   ?                       ; Ticks till we shutdown
  85. Idle_Max   dw   ?                       ; Initial ticks
  86.  
  87. Save_Reg   db   ?                       ; Place to save CRT register value
  88. Multiplex_No db  ?                       ; Multiplex number we're using
  89. Disabled   db   ?                       ; enable/disable flag
  90.  
  91. ;
  92. ; Define command line in PSP...
  93. ;
  94.         org     080h
  95. Cmdline label   byte
  96.         page
  97. ;  Code starts at offset 0100h for COM file.
  98.         org     0100h                   ; beginning for .com programs
  99. Start:  jmp     Initialize              ; initialization code is at end.
  100.  
  101. ;
  102. ; int 15 (system services) enters here.  Checks for keyboard intercept
  103. ; which shows some activity.  Passed on to old interrupt routine in all
  104. ; cases.
  105. ;
  106. System_Services proc far
  107.         cmp     ah,Keyboard_Intercept
  108.         jne     NotKey
  109.         call    Action                  ; record something happenned
  110. NotKey: jmp     Old_Ss                  ; pass it on to old routine
  111. System_Services endp
  112.  
  113. ;
  114. ; int 74h (mouse) enters here.  This also shows there is user activity.
  115. ;
  116. Mouse   proc   far
  117.         call    Action                  ; record something happenned
  118.         jmp     Old_Mouse               ; pass it on
  119. Mouse   endp
  120.  
  121. ;
  122. ;  Common processing for keyboard and mouse action.
  123. ;  Reset timeout interval; turn screen back on if it was off.
  124. ;
  125. Action  proc    near
  126.         push    ax                      ; save a register
  127.         cmp     Idle_Count,0            ; have we reached zero
  128.         jne     Reset                   ; no, just reset count
  129.  
  130. ;  Count had reached zero, so we would have disabled the screen.
  131. ;  Need to turn it back on here.
  132.         push    dx
  133.         mov     dx,SAR                  ; Get the current SDR index
  134.         in      al,dx                   ; ... value and save it
  135.         push    ax                      ; ...
  136.         mov     al,Clocking_Mode_Index  ; Then point it to clocking mode
  137.         out     dx,al                   ; ... register.
  138.         mov     dx,SDR                  ; Set the clocking mode register
  139.         mov     al,Save_Reg             ; ... back to what it was
  140.         out     dx,al
  141.         mov     dx,SAR                  ; Reset SAR to what it was
  142.         pop     ax                      ; ...
  143.         out     dx,al                   ; ...
  144.         pop     dx
  145.  
  146. Reset:  mov     ax,Idle_Max             ; reset count to max
  147.         mov     Idle_Count,ax           ; ...
  148.  
  149.         pop     ax                      ; restore
  150.         ret                             ; return
  151.  
  152. Action  endp
  153.  
  154. ;
  155. ; int 1ch (timer tick) enters here. If blanking enabled, decrement count
  156. ; and see if time to blank screen.
  157. ;
  158. Timer   proc    far
  159.  
  160.         cmp     Disabled,True           ; are we active?
  161.         je      Done                    ; no, quit
  162.         cmp     Idle_Count,0            ; already turned off?
  163.         je      Done                    ; ok, nothing to do
  164.  
  165.         dec     Idle_Count              ; subtract one...
  166.         jnz     Done                    ; quit if still nonzero
  167.  
  168. ; Count has reached zero.  Turn off the display.
  169.         push    dx
  170.         push    ax
  171.         mov     dx,SAR                  ; Get the current SDR index
  172.         in      al,dx                   ; ... value and save it
  173.         push    ax                      ; ...
  174.         mov     al,Clocking_Mode_Index  ; Then point it to clocking mode
  175.         out     dx,al                   ; ... register.
  176.         mov     dx,SDR                  ; Get the clocking mode register
  177.         in      al,dx                   ; ...
  178.         mov     Save_Reg,al             ; Save it away for later
  179.         or      al,Screen_Mask          ; set the video off bit
  180.         out     dx,al                   ; ...
  181.         mov     dx,SAR                  ; Reset SAR to what it was
  182.         pop     ax                      ; ...
  183.         out     dx,al                   ; ...
  184.         pop     ax
  185.         pop     dx
  186.  
  187. Done:   jmp     Old_Timer               ; continue with other int routine.
  188. Timer   endp
  189.         page
  190. ;
  191. ; int 2fh (Multiplex) enters here.  This is used for communication from
  192. ; later runs of Scrnsav2 program.
  193. ;
  194. Multiplex proc far
  195.         cmp     ah,Multiplex_No         ; is this our number?
  196.         je      Mine                    ; yes,...
  197.         jmp     Old_Multiplex           ; no, pass it on.
  198.  
  199. Mine:   cmp     al,Get_Installed_State  ; are we just testing?
  200.         jne     Mine2                   ; work to do
  201.  
  202. ; Set result to indicate installed.  Also, pass back our name as further
  203. ; check for someone else using the number.
  204.         mov     al,0ffh                 ; code to say we're here
  205.         push    ds                      ; copy ds to es
  206.         pop     es                      ; ...
  207.         lea     di,es:Scrnsav_Str       ; offset for our name
  208.         iret                            ; return it to caller.
  209.  
  210. ; Look for other function requests
  211. Mine2:  cmp     al,Scrnsav_Enable
  212.         jne     Mine3
  213.         mov     Disabled,False          ; set enabled
  214.         jmp     Valid
  215.  
  216. Mine3:  cmp     al,Scrnsav_Disable
  217.         jne     Mine4
  218.         mov     Disabled,True           ; set disabled
  219.         jmp     Valid
  220.  
  221. Mine4:  cmp     al,Scrnsav_Set_Interval
  222.         jne     Invalid
  223.         mov     Idle_Max,bx             ; reset interval
  224.  
  225. Valid:  mov     al,0                    ; set success code
  226.         iret
  227.  
  228. Invalid: mov    al,1                    ; return error code
  229.         iret
  230.  
  231. Scrnsav_Str db "SCRNSAV2"
  232.  
  233. Multiplex endp
  234.         page
  235. ;
  236. ; Initialization.  Print a greeting, process the parameters, determine
  237. ; whether already loaded, then either stay resident or communicate
  238. ; with resident version.
  239. ;
  240. Initialize proc near
  241.         assume  ds:Scrnsav2
  242.         push    bx                      ; save registers we use
  243.         push    cx
  244.         push    si
  245.         push    di
  246.         push    ds
  247.         push    es
  248.         push    dx
  249.  
  250.         push    cs                      ; copy cs to ds.
  251.         pop     ds
  252.  
  253.         cld                             ; always want to increment
  254.  
  255.         mov     dx,offset Greeting      ; message address
  256.         mov     ah,Print_String         ; function code
  257.         int     Dos@                    ; write the message
  258.  
  259. ; Determine if this will work on the machine we're running on.
  260.         mov     ax,Read_Display_Combination_Code   ; function code
  261.         int     Video_Io@               ; Bios call
  262.         cmp     al,1ah                  ; is it supported?
  263.         jne     NoVGA                   ; nope; so wrong machine
  264.         cmp     bl,07h                  ; VGA mono?
  265.         je      HaveVGA                 ; ...
  266.         cmp     bl,08h                  ; VGA color?
  267.         je      HaveVGA                 ; ...
  268.  
  269. NoVGA:  mov     dx,offset VGA_Message
  270.         mov     ah,Print_String         ; function code
  271.         int     Dos@                    ; write the message
  272.         jmp     Unload
  273.  
  274. ;
  275. ; Process the parameters. Should be integer number of minutes,
  276. ; and/or /d (disable), /e (enable), /m <int>
  277. ;
  278. HaveVGA:
  279.         mov     si,offset Cmdline       ; index of parameters
  280.         lodsb                           ; pick up count and step
  281.         mov     ah,0                    ; extend
  282.         mov     cx,ax                   ; copy to count register
  283. Next_Par:
  284.         call    Skipblanks              ; find first character
  285.         jnz     Have_Par                ; count reached zero
  286.         jmp     End_Pars
  287. Have_Par:
  288.         cmp     byte ptr [si],'/'       ; option flag?
  289.         jne     Try_Int
  290.         inc     si                      ; step to flag char
  291.         dec     cx                      ; decrement count
  292.         jz      Bad_Flag                ; missing flag spec
  293.  
  294.         cmp     byte ptr [si],'d'       ; test for disable flag
  295.         je      Disable
  296.         cmp     byte ptr [si],'D'
  297.         jne     Try_E                   ; not disable
  298. Disable: mov    Par_Disable,True        ; set the flag
  299.         inc     si                      ; step over it
  300.         dec     cx                      ; adjust count
  301.         jmp     Next_Par                ; and look for more pars
  302.  
  303. Try_E:  cmp     byte ptr [si],'e'       ; test for enable flag
  304.         je      Disable
  305.         cmp     byte ptr [si],'E'
  306.         jne     Try_M                   ; not enable
  307. Enable: mov     Par_Disable,False       ; set the flag
  308.         inc     si                      ; step over it
  309.         dec     cx                      ; adjust count
  310.         jmp     Next_Par                ; and look for more pars
  311.  
  312. Try_M:  cmp     byte ptr [si],'m'       ; test for m flag
  313.         je      M_Flag
  314.         cmp     byte ptr [si],'M'
  315.         jne     Bad_Flag                ; invalid flag
  316. M_Flag: inc     si                      ; step over it
  317.         dec     cx                      ; adjust count
  318.         call    Skipblanks              ; need a following integer par
  319.         jz      Bad_M_Flag              ; no following par
  320.         call    GetI                    ; find a number
  321.         jo      Bad_M_Flag              ; it overflows
  322.         jz      Bad_M_Flag              ; it wasn't there
  323.         cmp     ax,80h                  ; check the range
  324.         jl      Bad_M_Flag              ; ... too small
  325.         cmp     ax,0ffh                 ; ...
  326.         ja      Bad_M_Flag              ; ... too big
  327.         mov     Par_Multiplex_No,al     ; just right
  328.         jmp     Next_Par                ; look for more
  329.  
  330. ; Not a flag; should be integer number of minutes.
  331. Try_Int:
  332.         call    GetI                    ; find a number
  333.         jo      Too_Big                 ; it overflowed
  334.         jz      Bad_Par                 ; not found
  335.         cmp     ax,Max_Time             ; is it too big?
  336.         ja      Too_Big                 ; yes, don't allow.
  337.         mov     Par_Minutes,ax          ; save it away
  338.         mov     Par_Set_Interval,True   ; remember it was specified
  339.         jmp     Next_Par                ; look for more
  340.  
  341. ; Invalid flag; back up to the / character before echoing it.
  342. Bad_Flag:
  343.         dec     si                      ; back up one pos
  344.         inc     cx                      ; increase count
  345. Bad_Par: mov    dx,offset Bad_Par_Message
  346.         mov     ah,Print_String         ; function code
  347.         int     Dos@                    ; write the message
  348. Echo:   lodsb                           ; get next character
  349.         cmp     al,' '                  ; stop at a blank
  350.         je      End_Echo
  351.         mov     dl,al                   ; and echo it
  352.         mov     ah,Print_Char           ; ...
  353.         int     Dos@                    ; ...
  354.         loop    Echo
  355. End_Echo:
  356.         mov     dx,offset Bad_Par_Message2
  357.         mov     ah,Print_String         ; function code
  358.         int     Dos@                    ; write the end of the message
  359.         jmp     Unload
  360.  
  361. Too_Big: mov    dx,offset Too_Big_Message
  362.         mov     ah,Print_String         ; function code
  363.         int     Dos@                    ; write the message
  364.         jmp     Unload
  365.  
  366. Bad_M_Flag:
  367.         mov     dx,offset Bad_M_Flag_Message
  368.         mov     ah,Print_String         ; function code
  369.         int     Dos@                    ; write the message
  370.         jmp     Unload
  371.  
  372.         page
  373. ;
  374. ;  Parameter processing finished.
  375. ;
  376. End_Pars:
  377.         mov     ax,Par_Minutes          ; compute ticks required
  378.         mul     Ticks                   ; ...
  379.         mov     Par_Ticks,ax            ; ...
  380.  
  381. ;
  382. ;  Determine whether already installed.
  383. ;
  384.         mov     ah,Par_Multiplex_No     ; ask if already installed...
  385.         mov     al,Get_Installed_State  ; ...
  386.         int     Multiplex@              ; ...?
  387.         cmp     al,0                    ; is it installed?
  388.         je      Install                 ; no, go do it
  389.         cmp     al,0ffh                 ; seems to be, make sure
  390.         jne     Cant_Install            ; something wrong
  391. ;  Last test: if it is installed, should get back es:di pointing to
  392. ;  our name.
  393.         lea     si,Scrnsav_Str
  394.         mov     cx,size Scrnsav_Str
  395.         repnz   cmpsb                   ; compare the bytes
  396.         jne     Cant_Install
  397.  
  398. ;
  399. ;  Seems to be already installed, so pass across requested state.
  400. ;
  401.         mov     ah,Par_Multiplex_No     ; First set enabled/disabled.
  402.         mov     al,Scrnsav_Enable       ; assume enabling
  403.         cmp     Par_Disable,True        ; are we really?
  404.         jne     Send_Enable             ; ...
  405.         mov     al,Scrnsav_Disable      ; ... nope
  406. Send_Enable:
  407.         int     Multiplex@              ; Send it to resident copy.
  408.         cmp     al,0                    ; check for problems
  409.         jne     Cant_Change
  410.  
  411.         cmp     Par_Set_Interval,True   ; Do we want to change interval?
  412.         jne     No_Change
  413.         mov     ah,Par_Multiplex_No     ; yes, set up parameters
  414.         mov     al,Scrnsav_Set_Interval ; ...
  415.         mov     bx,Par_Ticks            ;...
  416.         int     Multiplex@              ; Send it to resident copy.
  417.         cmp     al,0                    ; check for problems
  418.         jne     Cant_Change
  419.  
  420. ;
  421. ; Write out what we did.
  422. ;
  423. No_Change:
  424.         mov     ax,offset Null_Message  ; no "installed and" part
  425.         call    Write_Status            ; call common routine
  426.         jmp     Unload_Ok               ; and terminate
  427.  
  428. ;
  429. ; Problems
  430. ;
  431. Cant_Install:
  432.         mov     dx,offset Cant_Install_Message
  433.         mov     ah,Print_String         ; function code
  434.         int     Dos@                    ; write the message
  435.         jmp     Unload
  436.  
  437. Cant_Change:
  438.         mov     dx,offset Cant_Change_Message
  439.         mov     ah,Print_String         ; function code
  440.         int     Dos@                    ; write the message
  441.         jmp     Unload
  442.  
  443.         page
  444.  
  445. ;
  446. ;  Appears to be OK to install, so lets do so.
  447. ;
  448. Install:
  449.         mov     al,Par_Disable          ; Set enable/disable state
  450.         mov     Disabled,al             ; ...
  451.         mov     ax,Par_Ticks            ; And interval
  452.         mov     Idle_Count,ax           ; ...
  453.         mov     Idle_Max,ax             ; ...
  454.         mov     al,Par_Multiplex_No     ; and multiplex number
  455.         mov     Multiplex_No,al         ; ...
  456.  
  457. ;
  458. ; Set up the interrupt vectors
  459. ;
  460.         mov     ah,Get_Int
  461.         mov     al,System_Services@     ; Get int 15.
  462.         int     Dos@
  463.         mov     Old_Ss,bx               ; Save it away
  464.         mov     Old_Ss+2,es
  465.         mov     ah,Set_Int
  466.         mov     al,System_Services@     ; Set new int 15.
  467.         mov     dx,offset System_Services
  468.         int     Dos@                    ; ...
  469.  
  470.         mov     ah,Get_Int
  471.         mov     al,Mouse@               ; Get int 74.
  472.         int     Dos@
  473.         mov     Old_Mouse,bx            ; Save it away
  474.         mov     Old_Mouse+2,es
  475.         mov     ah,Set_Int
  476.         mov     al,Mouse@               ; Set new int 74
  477.         mov     dx,offset Mouse
  478.         int     Dos@                    ; ...
  479.  
  480.         mov     ah,Get_Int
  481.         mov     al,Multiplex@           ; Get int 2f.
  482.         int     Dos@
  483.         mov     Old_Multiplex,bx        ; Save it away
  484.         mov     Old_Multiplex+2,es
  485.         mov     ah,Set_Int
  486.         mov     al,Multiplex@           ; Set new int 2f
  487.         mov     dx,offset Multiplex
  488.         int     Dos@                    ; ...
  489.  
  490.         mov     ah,Get_Int
  491.         mov     al,Timer@               ; Get int 1c
  492.         int     Dos@
  493.         mov     Old_Timer,bx           ; Save it away
  494.         mov     Old_Timer+2,es
  495.         mov     ah,Set_Int
  496.         mov     al,Timer@               ; Set new int 1c.
  497.         mov     dx,offset Timer
  498.         int     Dos@                    ; ...
  499.  
  500. ;
  501. ;  Put out a message saying what we did.
  502. ;
  503.         mov     Par_Set_Interval,True   ; always include the interval
  504.         mov     ax,offset Installed_Message
  505.         call    Write_Status            ; call common code
  506.  
  507. ;
  508. ;  Terminate and stay resident.
  509. ;
  510.         mov     ah,TSR                  ; terminate/stay resident
  511.         mov     al,0                    ; ... with exit code 0
  512.         pop     dx                      ; pop this off here... we don't restore it
  513.         mov     dx,((offset Initialize - offset Scrnsav2) + 15)/16
  514.         jmp     Return
  515.  
  516. ;  Terminate and unload (OK)
  517. Unload_Ok:
  518.         mov     al,00h                  ; Error code 0
  519.         jmp     Unload2                 ; merge
  520.  
  521. ;  Terminate and unload with error code.
  522. Unload: mov     al,01h                  ; with error code 1
  523. Unload2: mov    ah,Terminate            ; terminate
  524.         pop     dx                      ; restore dx
  525.  
  526. Return:
  527.         pop     es
  528.         pop     ds
  529.         pop     di
  530.         pop     si
  531.         pop     cx                      ; restore registers
  532.         pop     bx
  533.         int     Dos@                    ; back to DOS.
  534. Initialize endp
  535.         page
  536. ;
  537. ;  Write_Status writes a message saying what we did.
  538. ;
  539. ; At entry:     ax = message "installed and" if required.
  540. ;
  541. Write_Status proc near
  542.         push    dx                      ; save reg we clobber
  543.         push    ax                      ; save parameter
  544.         mov     dx,offset Status_Message ; "Screen saver "
  545.         mov     ah,Print_String
  546.         int     Dos@
  547.  
  548.         pop     dx                      ; "installed and "
  549.         mov     ah,Print_String
  550.         int     Dos@
  551.  
  552.         mov     dx,offset Enabled_Message ; "enabled"
  553.         cmp     Par_Disable,True
  554.         jne     Ws_Enable
  555.         mov     dx,offset Disabled_Message ; "disabled"
  556. Ws_Enable:
  557.         mov     ah,Print_String
  558.         int     Dos@
  559.  
  560.         cmp     Par_Set_Interval,True
  561.         jne     Ws_Done
  562.  
  563.         mov     dx,offset Lpar_Message  ; " ("
  564.         mov     ah,Print_String
  565.         int     Dos@
  566.  
  567.         mov     ax,Par_Minutes          ; <integer>
  568.         call    WriteI
  569.  
  570.         mov     dx,offset Rpar_Message  ; " minutes)"
  571.         mov     ah,Print_String
  572.         int     Dos@
  573.  
  574. Ws_Done:
  575.         mov     dx,offset End_Message   ; "."
  576.         mov     ah,Print_String
  577.         int     Dos@
  578.  
  579.         pop     dx                      ; restore reg
  580.         ret
  581.  
  582. Write_Status endp
  583.  
  584.         page
  585. ;
  586. ; Skipblanks skips over blanks and returns at non blank.
  587. ;
  588. ; At entry:   si = index of first byte to check
  589. ;             cx = count of characters in string
  590. ;
  591. ; At return:  si = index of non blank
  592. ;             cx = remaining characters
  593. ;             z bit = clear if non blank found
  594. ;                   = set if no nonblanks
  595. ;
  596. ; (Could do this with a rep scsb instruction, but setting it up
  597. ; is more hassle than its worth...)
  598. ;
  599. Skipblanks proc near
  600.  
  601. Sb_Loop:
  602.         cmp     cx,0                    ; any charaters left?
  603.         je      Sb_Ret                  ; nope
  604.         cmp     byte ptr [si],' '       ; is it blank?
  605.         jne     Sb_Ret                  ; nope, found something
  606.         inc     si                      ; step to next
  607.         dec     cx                      ; decrement count
  608.         jmp     Sb_Loop                 ; ... and continue
  609. Sb_Ret:
  610.         ret
  611. Skipblanks endp
  612.         page
  613. ;
  614. ; GetI converts an ascii string to an integer. It returns
  615. ; on encountering a non-digit.
  616. ;
  617. ; At entry:   si = index of first byte to convert
  618. ;             cx = count of characters in string
  619. ;
  620. ; At return:  si = index of first non digit
  621. ;             cx = remaining characters
  622. ;             ax = converted integer
  623. ;             o bit is set if result overflows a single register
  624. ;             z bit = clear if integer found
  625. ;                   = set if no integer
  626. ;
  627. GetI    proc near
  628.         push    bx
  629.         push    dx
  630.         push    cx                      ; copy cx for testing at end
  631.         cmp     cx,0                    ; see if we have any characters
  632.         jz      Gi_Ret                  ; ... and return if not.
  633.  
  634.         mov     ax,0                    ; initialize result in ax
  635. Gi_Loop: mov    bl,[si]                 ; pick up a byte
  636.         cmp     bl,'0'                  ; check it is in range
  637.         jb      Gi_Ret                  ; ...
  638.         cmp     bl,'9'                  ; ...
  639.         ja      Gi_Ret                  ; ...
  640.         inc     si                      ; step to next character
  641.  
  642.         mul     Ten                     ; accumulate result in ax/dx
  643.         jo      Gi_RetO                 ; overflowed
  644.         sub     bl,'0'                  ; convert digit to 0 ... 9
  645.         mov     bh,0                    ; ... word value
  646.         add     ax,bx                   ; add to result so far
  647.         jo      Gi_RetO                 ; overflowed
  648.         loop    Gi_Loop                 ; decrement count and continue
  649.         jmp     Gi_Ret                  ; merge below
  650.  
  651. Gi_RetO: pop    bx                      ; pop off saved cx
  652.         jmp     Gi_Ret2                 ; merge below
  653.  
  654. Gi_Ret: pop     bx                      ; pop back saved cx
  655.         cmp     bx,cx                   ; and set z bit to whether we found num
  656. Gi_Ret2: pop     dx                     ; restore regs (z or o bits set)
  657.         pop     bx                      ; ...
  658.         ret
  659. GetI    endp
  660.  
  661.         page
  662. ;
  663. ; WriteI converts a positive, word, integer to characters and writes
  664. ; them to stdout.   It uses recursion to emit the digits in the
  665. ; right order.
  666. ;
  667. ; At entry:     ax = number to convert
  668. ;
  669. WriteI  proc    near
  670.         push    dx                      ; save reg we use
  671.         cmp     ax,10                   ; more than one digit?
  672.         jb      Wi_Digit                ; nope, just do the digit
  673.  
  674.         mov     dx,0                    ; extend the dividend
  675.         div     Ten                     ; quot-> ax, rem-> dx
  676.         call    WriteI                  ; handle the quotient
  677.         mov     ax,dx                   ; followed by the remainder
  678.  
  679. Wi_Digit:
  680.         add     al,'0'                  ; convert digit to char
  681.         mov     dl,al                   ; and write it out...
  682.         mov     ah,Print_Char
  683.         int     Dos@
  684.  
  685.         pop     dx                      ; restore
  686.         ret                             ; and return
  687.  
  688. WriteI  endp
  689.         page
  690. ;
  691. ;  Data area used during option parsing.
  692. ;
  693. Par_Disable db  False                   ; Flags for options ...
  694. Par_Set_Interval db False               ; ... specified
  695. Par_Multiplex_No db Scrnsav_Multiplex_Number ; default number to use
  696. Par_Minutes dw  Default_Time            ; interval in minutes
  697. Par_Ticks   dw  ?                       ; interval in ticks
  698.  
  699. ;  Constants for mul/div instructions
  700. Ticks   dw      Ticks_Per_Minute
  701. Ten     dw      10
  702.  
  703. ; Message emitted
  704. Greeting db     'Scrnsav2 version 2.0.  (c) Alan Ballard 1988.',Cr,Lf,'$'
  705. VGA_Message db  Cr,Lf,'PS/2 with VGA adaptor is required.',Cr,Lf,'$'
  706. Bad_Par_Message db Cr,Lf,'Invalid command parameter: "$'
  707. Bad_Par_Message2 db '".',Cr,Lf
  708.         db      '   Parameters are',Cr,Lf
  709.         db      '      integer    (number of minutes till blanking)',Cr,Lf
  710.         db      '      /d         (disable blanking)',Cr,Lf
  711.         db      '      /e         (enable blanking)',Cr,Lf
  712.         db      '      /m integer (change multiplex number used)',Cr,Lf
  713.         db      '$'
  714. Too_Big_Message db Cr,Lf,'Blanking time too big.  Maximum is 30.',Cr,Lf, '$'
  715. Bad_M_Flag_Message db Cr,Lf,'Invalid /m option.  Must be followed by '
  716.         db      'number between 128 and 255.',Cr,Lf,'$'
  717. Cant_Install_Message db Cr,Lf,"Can't install SCRNSAV2.  "
  718.         db      'Try a different "multiplex number" (/m option).',Cr,Lf,'$'
  719. Cant_Change_Message db Cr,Lf,"Problems communicating with installed SCRNSAV2.  "
  720.         db      'Try a different "multiplex number" (/m option).',Cr,Lf,'$'
  721.  
  722. Status_Message    db 'Screen saver $'
  723. Installed_Message db 'installed and $'
  724. Null_Message      db '$'
  725. Enabled_Message   db 'enabled$'
  726. Disabled_Message  db 'disabled$'
  727. Lpar_Message      db ' ($'
  728. Rpar_Message      db ' minutes)$'
  729. End_Message       db '.',Cr,Lf,'$'
  730.  
  731. Scrnsav2 ends
  732.  
  733.  
  734.         end Start
  735.