;       SCCSID = @(#)inimsg3.asm        6.1 90/11/17
        page    78,132
SCCSID  equ     "@(#)inimsg3.asm        1.24 90/10/10"

;                 IBM/Microsoft Confidential
;
;           Copyright (c) IBM Corporation  1987, 1990
;           Copyright (c) Microsoft Corp.  1987, 1990
;                     All Rights Reserved
;
;  Change History:
;
; 155040 05/16/96 TPL   Protect syiSICGMessageR3 from faulting when being
;                       called in indirectly through syiDisplaySavedMessagesR3
;                       DS set to [syiMessageSelector] and not DOSINITDATA

.xlist
include dosseg.inc
include basemaca.inc
include osmaca.inc
include basemid.inc
include doshlp.inc
include fnoinit.inc
include inisms.inc
include mi.inc
include sicg.inc
include struc.inc
include utilmd17.inc
.list

        ModName  , FNO_INIMSG3_ASM
        CpuMode 386

        extrn   MESSAGE_BUFFER_LENGTH:abs

        ReferInitGlobal CFG_Prompt,byte
        ReferInitGlobal decimalascii,byte
        ReferInitGlobal error_messages_displayed,byte
        ReferInitGlobal message_buffer,byte
        ReferInitGlobal message_file_name,byte
        ReferInitGlobal message_length,word
        ReferInitGlobal pDosGetMessage,dword
        ReferInitGlobal pDosPutMessage,dword
        ReferInitGlobal pKbdFlushBuffer,dword
        ReferInitGlobal pKbdStringIn,dword
        ReferInitGlobal pPanicWrite,dword
        ReferInitGlobal pSICG,dword
        ReferInitGlobal sicg_packet_6,word
        ReferInitGlobal sicg_packet_6_d,byte
        ReferInitGlobal standard_output_handle,word
        ReferInitGlobal syiLostMessages,word
        ReferInitGlobal syiMessageSelector,word
        ReferInitGlobal syiSavedMessageIndicator,byte
        ReferInitGlobal tbl_lost_messages,byte
        ReferInitGlobal tbl_prompt,byte

        extrn   SYIAbort:near
        extrn   syiRetrieveMessage:near
        extrn   syiDisplayMessage:near
        extrn   SYISaveMessage:near

INITDATA segment
reply           db     ?              ; reply buffer
reply_length    equ    $-reply        ; length of reply buffer

;       The following two declarations must remain together since
;       they form a structure passed to KbdStringIn

reply_table     dw     reply_length   ; length of reply buffer
bytes_read      dw     ?              ; number of bytes read
INITDATA ends


        FARCODE INITR3
INITR3CODE segment

;***LP  syiDisplaySavedMessagesR3 - Display saved messages
;
;       To display all messages which were previously generated during
;       System Initialization, and free the message segment.
;
;       ENTRY   syiMessageSelector contains the message segment selector
;       EXIT    NONE
;       USES    AX, BX, CX, DX, SI, DI, Flags
;
;       for (each message in the message segment)
;         call syiDisplayMessageR3(message table) to display the message
;
;       if (any messages were lost)
;         call syiWordToDeR3c to convert # of messages lost to ASCIIZ string
;         call syiDisplayMessageR3(lost messages)

Procedure syiDisplaySavedMessagesR3
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>

;       Display all saved messages

;       Indicate being called by SaveMessage
        mov      syiSavedMessageIndicator,1

        SaveReg <ds>
        mov     ds,[syiMessageSelector]
        ASSUME DS:nothing
        mov     di,ds:[0].SMS_First     ; point to first message table element

        DosInitContext <es>

        .while  <nonzero di>
          lea   si,[di].SMS_SMT         ; point to message table
          .if <ds:[si].SMT_Message_ID ne MSG_REPLACEMENT_STRING>
             call  syiDisplayMessageR3     ; display this message
          .else   ;special case for MSG_REPLACEMENT_STRING
             SaveReg <es,ds>
             DosInitContext es
             mov     es:[sicg_packet_6_d].si6_pfn,offset syiDisplayMessage
             mov     es:[sicg_packet_6_d].si6_psmt.Segmt,ds
             mov     es:[sicg_packet_6_d].si6_psmt.Offst,si
             DosInitContext ds
             push    ds
             push    offset sicg_packet_6
             call    ds:[pSICG]                 ; Call SICG to do the work.
             call    syiPauseOnErrorR3
             RestoreReg <ds,es>
          .endif
          mov   di,ds:[di].SMS_Next     ; point to next message table element
        .endwhile
        RestoreReg <ds>

        mov      syiSavedMessageIndicator,0

;       Tell the user if any messages were lost

        .if     <[syiLostMessages] ne 0>
          mov   ax,[syiLostMessages]
          mov   di,offset decimalascii
          push  ds
          pop   es
          call  syiWordToDecR3          ; *(es:di) = ascii(ax)
          mov   si,offset tbl_lost_messages
          call  syiDisplayMessageR3
        .endif

;       Initialize the header fields in the message segment
;       so we can save more messages and display them again if needed

        DosInitContext ds
        mov     ds,[syiMessageSelector]

        mov     ds:[0].SMS_Size,SMS_default_size
        mov     ds:[0].SMS_First,0
        mov     ds:[0].SMS_Last,0
        mov     ds:[0].SMS_Free,size SMS


        RestoreReg <es,ds>
        ret
EndProc syiDisplaySavedMessagesR3


;***LP  syiDisplayMessageR3 - Display a message
;
;       Retrieve and display an error message and prompt the user to read
;       an error message.
;
;       ENTRY   (DS:SI) = Address of SysInit Message Table (SMT)
;                         containing the following data:
;                          SMT_Message_ID = message ID
;                          SMT_No_Vars    = number of insertion items
;                          SMT_Var_Ptr    = address of ASCIIZ string
;                                           (repeated n times)
;       EXIT    NONE
;       USES    Flags
;
;       call syiRetrieveMessageR3(message table) to retrieve the message
;       if (this is an error message)
;           indicate an error message was displayed
;       call syiShowMessageR3(message buffer) to display the message
;       call syiPauseOnErrorR3 to display "press Enter key to continue"
;           if an error message was displayed

Procedure syiDisplayMessageR3,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Retrieve the message text and fill in variable text

        call    syiRetrieveMessageR3

;       See if this is an error message
;       NOTE: An error message is always prefixed with the message
;             identifier (SYSnnnn:), while an informational or
;             prompt message starts with the message text. Any
;             message which contains a colon in the 8th character
;             position is assumed to be an error message

        DosInitContext ds
        .if     <[message_buffer+7] eq ':'>
          mov   [error_messages_displayed],1
        .endif

        call    syiShowMessageR3        ; Display the message on the screen

;       If any error messages have been displayed and prompting is desired and
;       possible at this time, prompt the user to press Enter key to continue.

        call    syiPauseOnErrorR3

        popa
        RestoreReg <es,ds>
        ret
EndProc syiDisplayMessageR3


;***LP  syiRetrieveMessageR3 - Retrieve a message
;
;       Retrieve a message, either by using the message retriever, or by
;       supplying a pre-assembled message.
;
;       INPUT   (DS:SI) = Address of SysInit Message Table (SMT)
;                         containing the following data:
;                          SMT_Message_ID = message ID
;                          SMT_No_Vars    = number of insertion items
;                          SMT_Var_Ptr    = address of ASCIIZ string
;                                           (repeated n times)
;       EXIT    message_buffer contains the message
;               message_length contains the length of the message
;       USES    Flags
;
;       if (DosGetMessage has been found)
;           Call DosGetMessage(message ID,file = 'OSO001.MSG',
;                              number of insertions,
;                              insertion variable table,
;                              buffer,length) to retrieve the message
;       else
;           call SICG to do the DosGetMessage

Procedure syiRetrieveMessageR3,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        SaveReg <ds,es>
        pusha

;       See if the Message Retriever is available

        DosInitContext es
        .if     <[pDosGetMessage].Segmt ne 0>

;         Retrieve the message text and fill in variable text
;         Call DosGetMessage(ivt,number of variables,message buffer,
;                            length of buffer,message number,
;                            message file name,message length)

          push  ds                      ; address of insertion variable
          lea   ax,ds:[si+size SMT]     ; table
          push  ax
          push  ds:[si].SMT_No_Vars     ; number of variables
          push  es                      ; address of message buffer
          push  offset message_buffer
          push  MESSAGE_BUFFER_LENGTH   ; size of message buffer
          push  ds:[si].SMT_Message_ID; message number
          push  es                      ; address of message file name
          push  offset message_file_name
          push  es                      ; address of message length
          push  offset message_length
          push  0                       ; address of pre-assembled
          push  0                       ; message table
          call  [pDosGetMessage]
          .if   <ax ne 0>
             ;Problem with Message Retriever, try getting from OS2LDR.MSG
              mov   [sicg_packet_6_d].si6_pfn,offset syiRetrieveMessage
              call  syiSICGMessageR3        ; call SICG to do the work.
          .endif
        .else near

;         The Message Retriever is not available.

          mov   [sicg_packet_6_d].si6_pfn,offset syiRetrieveMessage
          call  syiSICGMessageR3        ; call SICG to do the work.
        .endif

        popa
        RestoreReg <es,ds>
    assume ds:nothing, es:nothing
        ret
EndProc syiRetrieveMessageR3


;***LP  syiShowMessageR3 - call API to display a message
;
;       Call DosPutMessage or PanicWrite to display a message.
;
;       INPUT   [message_buffer] contains the message
;               [message_length] contains the length of the message
;       EXIT    NONE
;       USES    Flags
;
;       if (the StdOut File has been opened && DosPutMessage has been found)
;           call DosPutMessage(standard output,buffer,length)
;       if (the message was not successfully displayed using DosPutMessage)
;           call PanicWrite(buffer, length)

Procedure syiShowMessageR3
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar bytes_written,WORD

        EnterProc
        SaveReg <ds,es>
        pusha

;       See if DosPutMessage can be used to display the message

        .if <[standard_output_handle] eq -1> or
        .if <[pDosPutMessage].Segmt eq 0>
           mov ax,-1                    ; can't use DosPutMessage
        .else

;         Display the message using the Message Retriever
;         Call DosPutMessage(handle,message length,message buffer)

          push [standard_output_handle] ; handle for Standard Output File
          push [message_length]         ; length of message
          push ds                       ; address of message buffer
          push offset message_buffer
          call [pDosPutMessage]
        .endif

;       If the message was not displayed successfully, display the
;       message using PanicWrite

        .if <ax ne 0>

;         Call PanicWrite(handle,message buffer,message length,bytes written

          push [standard_output_handle] ; handle for Standard Output File
          push ds                       ; address of message buffer
          push offset message_buffer
          push [message_length]         ; length of message
          push ss                       ; address of bytes written word
          lea  ax,[bytes_written]
          push ax
          call [pPanicWrite]
        .endif

        popa
        RestoreReg <es,ds>
        LeaveProc
        ret
EndProc syiShowMessageR3


;***LP  syiAbortR3 - Abort the System Initialization Process from ring 3
;
;       Display a fatal error message and halt the system.
;
;       ENTRY   (DS:SI) = Address of SysInit Message Table (SMT)
;                         containing the following data:
;                          SMT_Message_ID = message ID
;                          SMT_No_Vars    = number of insertion items
;                          SMT_Var_Ptr    = address of ASCIIZ string
;                                           (repeated n times)
;       EXIT    Does not return.
;       EFFECTS The sytem is halted.
;
;       CANNOT and DOES NOT use the message retriever.
;
;       call SICG to dispatch to ring 0 routine: SYIAbort

Procedure syiAbortR3
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        mov     [sicg_packet_6_d].si6_pfn,offset SYIAbort
        call    syiSICGMessageR3        ; call SICG to do the work.
EndProc syiAbortR3


;***    syiWordToDecR3 - converts a word to ASCII decimal number
;
;       The ascii decimal number has leading zeros removed, and may
;       contain as many as 6 bytes, including the trailing nul byte.
;       A 6 byte buffer is required!
;
;       ENTRY   (AX) contains the number to be converted
;               (ES:DI) point to destination
;       EXIT    (ES:DI) updated (points to trailing nul byte)
;       USES    AX, BX, DX, SI, DI, Flags

Procedure syiWordToDecR3
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        mov     bx,10                   ; (BX) = radix (base 10)
        mov     si,di                   ; (SI) = base of result
        add     di,4
        mov     byte ptr es:[di+1],0    ; nul-terminate initial string
        std                             ; build initial string backwards

wtd10:  xor     dx,dx                   ; (DX),(AX) = (0:AX) / (BX)
        div     bx                      ; (AX) = quotient, (DX) = remainder
        xchg    al,dl                   ; (AL) = remainder
        add     al,'0'                  ; (AL) = ascii digit
        stosb                           ; drop in the character
        xchg    al,dl                   ; (AX) = quotient from last division
        or      ax,ax                   ; stop when (AX) == 0
        jnz     short wtd10

        cld                             ; copy string from beginning
        xor     dx,dx                   ; indicate drop leading '0's
        inc     di                      ; point to first byte stored
        xchg    si,di                   ; (SI) = initial, (DI) = final

wtd60:  lods    byte ptr es:[si]        ; grab a byte
        cmp     al,'0'
        jnz     short wtd70             ; copy if not '0'
        or      dx,dx
        jnz     short wtd70             ; or not leading
        cmp     byte ptr es:[si],0
        jnz     short wtd60             ; or not at end of initial string
wtd70:  inc     dx
        stosb
        or      al,al
        jnz     short wtd60             ; stop after trailing nul

        RETC
EndProc syiWordToDecR3


;***LP  syiPauseOnErrorR3 - If possible, pause and wait for user input.
;
;       Prompt the user to read an error message.
;
;       ENTRY   NONE
;       EXIT    NONE
;       USES    Flags
;
;       if (prompting is desired)
;           call KbdFlushBuffer to flush the keyboard buffer
;           call syiRetrieveMessage(press Enter key to continue)
;           call syiShowMessage(message buffer) to display the message
;           call KbdStringIn(reply) to wait for the user to press Enter

Procedure syiPauseOnErrorR3
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       If any error messages have been displayed and prompting is
;       desired and possible at this time, prompt the user to
;       press the Enter key to continue

        DosInitContext ds
        .if     <[error_messages_displayed] ne 0> and
        .if     <[CFG_Prompt] ne 0> and
        .if     <[pKbdFlushBuffer].Segmt ne 0> and
        .if     <[pKbdStringIn].Segmt ne 0> and
        .if     <[pDosGetMessage].Segmt ne 0> and
        .if     <[pDosPutMessage].Segmt ne 0>

          push  0                       ; handle
          call  [pKbdFlushBuffer]       ; flush the input buffer

          mov   si,offset tbl_prompt    ; display the prompt
          call  syiRetrieveMessageR3
          call  syiShowMessageR3

          push  ds                      ; address of input buffer
          push  offset reply
          push  ds                      ; length of input buffer/
          push  offset reply_table      ; bytes read
          push  0                       ; wait for Enter
          push  0                       ; handle
          call  [pKbdStringIn]          ; wait for the user to press Enter

          mov   [error_messages_displayed],0 ; prompt was issued
        .endif

        popa
        RestoreReg <es,ds>
        ret
EndProc syiPauseOnErrorR3


;***EP  syiSaveMessageR3 - save message
;
;       Save the message ID and variable text of a message to be displayed
;       when the System Initialization Process is running.
;
;       ENTRY   (DS:SI) = address of SysInit Message Table (SMT)
;                         containing the following data:
;                          SMT_Message_ID = message ID
;                          SMT_No_Vars    = number of insertion items
;                          SMT_Var_Ptr    = address of ASCIIZ string
;                                           (repeated n times)
;       EXIT    NONE
;       USES    Flags
;
;       call SICG to dispatch to ring 0 routine: SYISaveMessage

Procedure syiSaveMessageR3
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        mov     [sicg_packet_6_d].si6_pfn,offset SYISaveMessage
        call    syiSICGMessageR3
        ret
EndProc syiSaveMessageR3


;***LP  syiSICGMessageR3 - call ring 0 message routine
;
;       Pass the message on to the appropriate ring 0 message routine.
;
;       ENTRY   (DS:SI) = address of SysInit Message Table (SMT)
;                         containing the following data:
;                          SMT_Message_ID = message ID
;                          SMT_No_Vars    = number of insertion items
;                          SMT_Var_Ptr    = address of ASCIIZ string
;                                           (repeated n times)
;               [sicg_packet_6].si6_pfn filled in with ring 0 routine offset
;       EXIT    NONE
;       USES    Flags
;
;       call SICG to dispatch to ring 0 routine

Procedure syiSICGMessageR3,,local
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    bx                                                      ;155040
        mov     bx, ds                                                  ;155040
        DosInitContext ds                                               ;155040
        mov     [sicg_packet_6_d].si6_psmt.Segmt,bx                     ;155040
        mov     [sicg_packet_6_d].si6_psmt.Offst,si
        push    ds
        push    offset sicg_packet_6
        call    [pSICG]                 ; Call SICG to do the work.
        pop     bx                                                      ;155040
        ret
EndProc syiSICGMessageR3


INITR3CODE ends
        end
