Category : OS/2 Files
Archive   : OS2CMAPI.ZIP
Filename : FILEMREQ.ASM

 
Output of file : FILEMREQ.ASM contained in archive : OS2CMAPI.ZIP
.286p ;pseudo operand to enable 286 instructions
SUBTTL OS/2 Extended Edition - APPC Macro Assembler Sample Requester Program

;*************************************************************************;
; ;
; MODULE NAME : FILEMREQ.ASM ;
; ;
; DESCRIPTIVE NAME : APPC FILE REQUESTER MASM SAMPLE PROGRAM FOR ;
; OPERATING SYSTEM/2 EXTENDED EDITION ;
; ;
; COPYRIGHT: (C) COPYRIGHT IBM CORP. 1988 ;
; LICENSED MATERIAL - PROGRAM PROPERTY OF IBM ;
; ALL RIGHTS RESERVED ;
; ;
; STATUS: LPP Release 1.1 Modification 0 ;
; ;
; FUNCTION = Issues a request for a file to a server and ;
; transfers the file to the default local disk ;
; (current directory). All data transfer is to ;
; a peer server via APPC calls. The program is ;
; invoked: ;
; ;
; FILEMREQ filename ;
; ;
; The filename is a valid DOS filename on the server ;
; system. Both the server and requester sample programs ;
; use this filename for DOSOPEN so any subdirectory ;
; specified must be valid on both systems. ;
; ;
; Uses the following APPC Verbs: ;
; ;
; TP_STARTED ;
; MC_ALLOCATE ;
; MC_SEND_DATA ;
; MC_RECEIVE_AND_WAIT ;
; MC_CONFIRMED ;
; TP_ENDED ;
; ;
; Uses the following General Services verbs: ;
; ;
; CONVERT ;
; ;
; MODULE TYPE = IBM Personal Computer Macro Assembler/2 ;
; (Compiles with Small Memory Model) ;
; ;
; Requires message file "APX.MSG" at runtime. ;
; ;
;=========================================================================;
IF1
INCLUDE APPC_A.INC ;APPC include file
INCLUDE ACSSVCA.INC ;Adv. Comm. Genl. Svcs. include
INCLUDE SYSMAC.INC
ENDIF

@APPC MACRO VCB ;Define APPC Call Macro
@DEFINE APPC
@PUSHS VCB
CALL FAR PTR APPC
ENDM

@ACSSVC MACRO VCB ;Define General Services Call
@DEFINE ACSSVC ;Macro
@PUSHS VCB
CALL FAR PTR ACSSVC
ENDM

MV_CVID MACRO TGT,SRC ;Define move conversation_id macro
PUSH WORD PTR SRC+0
POP WORD PTR TGT+0
PUSH WORD PTR SRC+2
POP WORD PTR TGT+2
ENDM


MV_TPID MACRO TGT,SRC ;Define move tp-id macro
MV_CVID TGT+0,SRC+0
MV_CVID TGT+4,SRC+4
ENDM

DGROUP GROUP DATA

;=============================================================================
STACK SEGMENT WORD STACK 'STACK'
DW 1024 DUP (?)
STACK ENDS
;=============================================================================
DATA SEGMENT WORD PUBLIC 'DATA'

DB 'MREQUEST'
DB '(C) COPYRIGHT 1987 IBM Corp.'

MSG1 DB 'Unable to process message file - APX.MSG',0DH,0AH
MSG1_LEN EQU $-MSG1

PRIM_RCMSG DB ' ',0DH,0AH ;Primary return code msg.
PRIM_RCMSG_LEN EQU $-PRIM_RCMSG

SEC_RCMSG DB ' ',0DH,0AH ;Secondary RC message
SEC_RCMSG_LEN EQU $-SEC_RCMSG

COUNT_MSG DB ' H ',0DH ;byte count output + CR
COUNT_MSGLEN EQU $-COUNT_MSG

CRLF DB 0AH,0DH ;CR/LF to write a blank line

HEXTAB DB '0123456789ABCDEF' ;table for hex conversion

LUNAME1 DB 'FILEREQ ' ;my LU name
LUNAME2 DB 'FILESVR ' ;partner's LU name

; Names from MODENAME to CNVT_LEN will be converted from ASCII to EBCDIC

MODENAME DB 'MODE1 ' ;mode name
MODENAME_LEN EQU $-MODENAME ;ASCII to EBCDIC convert length
TP_NAME1 DB 'FILEMREQ ' ;64 byte name
DB 54 DUP (' ')
TP_NAME1_LEN EQU $-TP_NAME1
TP_NAME2 DB 'FILEMSVR ' ;64 byte name
DB 54 DUP (' ')
TP_NAME2_LEN EQU $-TP_NAME2 ;len to convert ASCII to EBCDIC

;=============================================================================

SYS_ERR DB 0 ;system err flag
DOS_EOF DB 0 ;DOS file eof flag
FILENAME_OK DB 0 ;good filename flag
FIRST_FLAG DB 0 ;first time thru flag

MSG_NO DW 0 ;message to load & display
MSG_LENGTH DW 0 ;length (set by OS/2)
MSG_FILENAME DB 'APX.MSG',0 ;message file name
MSG_BUFF DB 100 DUP (?) ;buffer for messages

ANB_PTR DD 0 ;AlphaNumericBuffer pointer
CONV_ID DB 4 DUP (?) ;APPC conversation id
TP_ID DB 8 DUP (?) ;APPC tp_id

DATA_LEN DW 0 ;bytes read by RCV_AND_WAIT
BYTES_OUT DW 0 ;bytes written (from DosWrite)

FILEHANDLE DW 0 ;filehandle from DosOpen
ACTION DW 0 ;action flag from DosOpen
FN_POINTER DD 0 ;pointer to filename
COUNT_HI DW 0 ;cuml. byte count - high word
COUNT_LO DW 0 ;cuml. byte count - low word

;============================================================================;
; VERB CONTROL BLOCK ;
;============================================================================;

MAL MC_ALLOC <>
ORG MAL ;use 1 VCB w/ STRUCTs
TPS TP_STARTED <> ;redefined over the same strge
ORG MAL
TPE TP_ENDED <>
ORG MAL
MRW MC_RCV_AND_WAIT <>
ORG MAL
MSD MC_SND_DATA <>
ORG MAL
MCM MC_CNFRMD <>
ORG MAL
CVT CONVERT <> ;Convert general service struct
ORG MAL
VCB DB 300 DUP (0) ;Verb Control Block
VCB_LEN EQU $-VCB ;set size of VCB


DATA ENDS

;=============================================================================

CSEG SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CSEG, DS:DGROUP


REQUEST PROC FAR

MOV WORD PTR FN_POINTER+2,AX ;save env. string selector
MOV WORD PTR FN_POINTER,BX ;save offset to command line

PUSH DS ;prepare destination seg reg
POP ES ;for all string moves

CALL INIT_SELF ;initialize
CALL PARSE_FILENAME ;get the requested name
CALL DO_TP_STARTED ;indicate a TP is started
CALL DO_MC_ALLOCATE ;allocate session & conversation
CALL SEND_FILENAME ;request the file
MAIN_LOOP:
CALL DO_RCV_AND_WAIT ;wait for data from the server
CMP MRW.PRIM_RC_MRW,WORD PTR AP_PROG_ERROR_NO_TRUNC
;check status
JE FILE_NOT_FOUND ;PROG_ERR = file not found
CMP MRW.PRIM_RC_MRW,WORD PTR AP_OK
;otherwise it should be ok
JE DATA_OK
CALL SHOW_ERR ;else is an APPC error
@DosExit 0,0 ;display msg & quit
FILE_NOT_FOUND:
MOV MSG_NO,14 ;'File not found' msg
CALL SHOW_MSG ;Display msg
JMP DONE ;then cleanup & exit
DATA_OK:
MOV AX,WORD PTR MRW.WHAT_RCVD_MRW
;get WHAT_RCVD indicator
CMP AX,WORD PTR AP_DATA_COMPLETE
;did we get good data ?
JE WRITE_DATA ;if so, go write it to the file
CMP AX,WORD PTR AP_CONFIRM_DEALLOCATE
;did we get an eof signal ?
JE HAVE_EOF ;if so, go confirm it
MOV MSG_NO,15 ;'Bad What_rcvd' msg
CALL SHOW_MSG
LEA DI,PRIM_RCMSG ;addr to convert data
CALL CVHEX ;AX to ASCII at DS:DI
@VioWrtTTY PRIM_RCMSG,PRIM_RCMSG_LEN,0
;display err code
JMP DONE ;go terminate
WRITE_DATA:
CALL WRITE_DOSFILE ;go write to disk file
JMP MAIN_LOOP ;then continue to process
HAVE_EOF:
CALL DO_MC_CONFIRMED ;issue MC_CONFIRMED
JMP DONE ;(could fall thru)
DONE:
@VioWrtTTY CRLF,2,0 ;write a blank line
CMP FILENAME_OK,0 ;did we open the file ?
JNE NEVER_OPEN ;if not, don't try to close it
CALL CLOSE_DOS_FILE ;else, close the input file
NEVER_OPEN:
CALL DO_TP_ENDED
@DosFreeSeg WORD PTR ANB_PTR+2 ;free the shared segment
MOV MSG_NO,3 ;'Function Complete' msg.
CALL SHOW_MSG
@DosExit 0,0 ;exit the program

;=============================================================================

INIT_SELF PROC
MOV MSG_NO,2 ;display msg 2 'Requester Program'
CALL SHOW_MSG
CALL ALLOC_SHARED_BUFFER ;APPC requires an unnamed shared
;segment for a data buffer
; APPC requires EBCDIC (vs. ASCII) for several values, convert them now.
CALL CLEAR_VCB ;zero the control block
MOV CVT.OPCODE_CVT,SV_CONVERT ;Convert opcode
MOV CVT.DIRECTION_CVT,SV_ASCII_TO_EBCDIC
;ASCII to EBCDIC
MOV CVT.CHAR_SET_CVT,SV_A ;select the translate
MOV CVT.LEN_CVT,MODENAME_LEN ;length to convert
LEA AX,MODENAME ;start of data to cnvt
MOV WORD PTR CVT.SRC_PTR_CVT,AX
;source offset
MOV WORD PTR CVT.TARG_PTR_CVT,AX
;convert in place
MOV WORD PTR CVT.SRC_PTR_CVT+2,DS
;set selector
MOV WORD PTR CVT.TARG_PTR_CVT+2,DS
;set selector
@ACSSVC VCB ;issue convert verb
CALL CLEAR_VCB ;zero the control block
MOV CVT.OPCODE_CVT,SV_CONVERT ;Convert opcode
MOV CVT.DIRECTION_CVT,SV_ASCII_TO_EBCDIC
;ASCII to EBCDIC
MOV CVT.CHAR_SET_CVT,SV_AE ;select the translate
MOV CVT.LEN_CVT,TP_NAME1_LEN ;length to convert
LEA AX,TP_NAME1 ;start of data to cnvt
MOV WORD PTR CVT.SRC_PTR_CVT,AX
;source offset
MOV WORD PTR CVT.TARG_PTR_CVT,AX
;convert in place
MOV WORD PTR CVT.SRC_PTR_CVT+2,DS
;set selector
MOV WORD PTR CVT.TARG_PTR_CVT+2,DS
;set selector
@ACSSVC VCB ;issue convert verb
CALL CLEAR_VCB ;zero the control block
MOV CVT.OPCODE_CVT,SV_CONVERT ;Convert opcode
MOV CVT.DIRECTION_CVT,SV_ASCII_TO_EBCDIC
;ASCII to EBCDIC
MOV CVT.CHAR_SET_CVT,SV_AE ;select the translate
MOV CVT.LEN_CVT,TP_NAME2_LEN ;length to convert
LEA AX,TP_NAME2 ;start of data to cnvt
MOV WORD PTR CVT.SRC_PTR_CVT,AX
;source offset
MOV WORD PTR CVT.TARG_PTR_CVT,AX
;convert in place
MOV WORD PTR CVT.SRC_PTR_CVT+2,DS
;set selector
MOV WORD PTR CVT.TARG_PTR_CVT+2,DS
;set selector
@ACSSVC VCB ;issue convert verb
RET
INIT_SELF ENDP

PARSE_FILENAME PROC

; Gets the requested filename from the command line and places it into the
; APPC shared buffer in the format: LL byte (length) + ASCIIZ string.
; Also sets far ptr FN_POINTER to the original filename (used by DosOpen).

PUSH ES ;save string dest seg reg
LES DI,FN_POINTER ;points to command line in env str
XOR AX,AX ;set AL = 00
MOV CX,100 ;max size to scan = 100 bytes
CLD ;set DF to increment
PF_SKIP_COMMAND:
SCAS ES:BYTE PTR [DI] ;look for 00 (end of command)
JE PF_NEXT ;we are now past the command
DEC CX ;else try again
JCXZ PF_BAD_ENV ;if we count out,something's wrong
JMP PF_SKIP_COMMAND ;keep looking for end of command
PF_NEXT:
CMP BYTE PTR ES:0 [DI],20H ;Usually we have a leading blank
JNE PF_NOADJ ;If not, the filename addr is ok
INC DI ;Else, increment to skip leading
;blank
JMP PF_NEXT ;Keep looking for first nonblank
PF_NOADJ:
MOV WORD PTR FN_POINTER,DI ;reset ptr to indicate ASCIIZ
;filename
XOR CX,CX ;string size = 0
MOV SI,01 ;offset into APPC buffer
;to put data
PF_LOOP:
MOV AL,BYTE PTR ES:[DI] ;get a byte of filename
CMP AL,00 ;end of file flag ?
JE PF_DONE ;if so we are done moving it
CMP AL,20H ;is it a blank ?
JE PF_SKIPIT ;if blank, skip it
PUSH ES
MOV ES,WORD PTR ANB_PTR+2 ;get selector of APPC buffer
MOV BYTE PTR ES:[SI],AL ;move the data
POP ES ;back to env string selector
INC SI ;SI = APPC buffer index
PF_SKIPIT:
INC DI ;DI = source index in env string
INC CX ;increment count
CMP CX,100 ;check for max size
JG PF_BAD_ENV ;if > 100 something is wrong, exit
JMP PF_LOOP ;go move another
PF_DONE:
MOV ES,WORD PTR ANB_PTR+2 ;point to APPC buffer
MOV BYTE PTR ES:[SI],00 ;keep it an ASCIIZ string
INC CX ;+ 1 for the 00
MOV BYTE PTR ES:0,CL ;also set the length at offset 0
POP ES ;restore string dest seg reg
RET

PF_BAD_ENV: ;error in env string
MOV MSG_NO,13 ;'File error - unable to open'
CALL SHOW_MSG ;call subr. to show message....
@DosExit 0,0 ;and quit
PARSE_FILENAME ENDP

SHOW_MSG PROC

; Displays a message from the message file APX.MSG. MSG_NO has the msg. number

PUSH AX ;save req
@DosGetMessage MSG_BUFF,0,MSG_BUFF,100,MSG_NO,MSG_FILENAME,MSG_LENGTH
;doscall to get message
CMP AX,0 ;check return code - is it good ?
JE SM_MSG_OK ;if so, go display message text
MOV SYS_ERR,01 ;if bad, flag system error status
@VioWrtTTY MSG1,MSG1_LEN,0 ;and show a hardcoded error msg
@DosExit 0,0 ;then terminate the program
SM_MSG_OK:
@VioWrtTTY MSG_BUFF,MSG_LENGTH,0 ;display the message
POP AX ;restore reg
RET ;and return
SHOW_MSG ENDP

SHOW_ERR PROC

;displays APPC error return codes
MOV MSG_NO,10 ;msg #10 = 'APPC Err, Primary RC='
CALL SHOW_MSG
MOV AX,MAL.PRIM_RC_MAL ;get the APPC primary_retcode
LEA DI,PRIM_RCMSG ;address to CVHEX into
CALL CVHEX ;conv AX: to printable hex at DI:
@VioWrtTTY PRIM_RCMSG,PRIM_RCMSG_LEN,0

MOV MSG_NO,11 ;'Secondary RC = '
CALL SHOW_MSG
MOV AX,WORD PTR MAL.SEC_RC_MAL+2
;get the APPC secondary rc
LEA DI,SEC_RCMSG
CALL CVHEX ;convert to displayable ASCII
MOV AX,WORD PTR MAL.SEC_RC_MAL
;get 2nd part of secondary_rc
LEA DI,SEC_RCMSG+4
CALL CVHEX ;convert it to printable hex
@VioWrtTTY SEC_RCMSG,SEC_RCMSG_LEN,0

MOV MSG_NO,18 ;'APPC Verb in error = '
CALL SHOW_MSG
MOV AX,WORD PTR MAL.OPCODE_MAL ;get the verb opcode
LEA DI,PRIM_RCMSG ;use same output line as before
CALL CVHEX ;make it printable
@VioWrtTTY PRIM_RCMSG,PRIM_RCMSG_LEN,0
RET
SHOW_ERR ENDP

SHOW_DOS_ERR PROC

; display error in DOS call. bad rc passed in AX:

PUSH DI ;save work reg.
PUSH AX ;save the error code
MOV MSG_NO,12 ;DOS error message #
CALL SHOW_MSG ;display the message
POP AX ;restore the DOS error code
PUSH AX ;save it again
LEA DI,PRIM_RCMSG ;get output line address
CALL CVHEX ;convert to display format
@VioWrtTTY PRIM_RCMSG,PRIM_RCMSG_LEN,0
;display the error code
POP AX ;restore the error code
POP DI
RET ;and return
SHOW_DOS_ERR ENDP

CLEAR_VCB PROC

; moves 00 to the verb control block (to reset all fields)

PUSH AX ;save existing regs
PUSH CX
PUSH DI
CLD
MOV AX, 0
MOV CX,VCB_LEN
LEA DI,VCB
REP STOSB ;zero the entire VCB
POP DI ;restore regs
POP CX
POP AX
RET ;and return
CLEAR_VCB ENDP

CVHEX PROC

; converts data in AX: into printable hex (4 bytes) at DS:DI

PUSH BX ;save work regs
PUSH CX
MOV BX,AX ;get hex data
AND BX,000FH ;cleanup to get just 1st nibble
MOV CL,HEXTAB[BX] ;lookup the ASCII representation
MOV [DI]+3,CL ;put it into the output area
MOV BX,AX ;reget the original data
AND BX,00F0H ;cleanup to get the 2nd nibble
MOV CL,04 ;shift it over for lookup index
SHR BX,CL
MOV CL,HEXTAB[BX] ;lookup the ASCII representation
MOV [DI]+2,CL ;put it into the result
MOV BX,AX ;reget the original
AND BX,0F00H ;3rd nibble
MOV CL,08 ;shift it
SHR BX,CL
MOV CL,HEXTAB[BX] ;lookup the ASCII rep.
MOV [DI]+1,CL ;into result
MOV BX,AX
AND BX,0F000H ;4th nibble
MOV CL,12 ;shift
SHR BX,CL
MOV CL,HEXTAB[BX] ;lookup
MOV [DI],CL ;save result
POP CX ;restore regs & exit
POP BX
RET
CVHEX ENDP


;============================================================================;
; ;
; APPC Related Subroutines ;
; ;
;============================================================================;

DO_TP_STARTED PROC
CALL CLEAR_VCB ;reset VCB to 00
MOV TPS.OPCODE_TPS,AP_TP_STARTED
;set verb opcode
CLD
MOV CX,8 ;tp_name is 64 bytes
LEA SI,LUNAME1 ;source is LUNAME1
LEA DI,TPS.LU_ALIAS_TPS ;destination is LU_ALIAS
REP MOVSB ;copy entire LUNAME1

MOV CX,64 ;tp_name is 64 bytes
LEA SI,TP_NAME1 ;source is at tp_name1
LEA DI,TPS.TP_NAME_TPS ;destination addr
REP MOVSB ;copy entire tp_name

@APPC VCB ;issue TP_STARTED verb
CMP TPS.PRIM_RC_TPS,WORD PTR AP_OK
;check return code - is it good ?
JE TPS_OK ;if so, continue
CALL SHOW_ERR ;else, display APPC error msg
@DosExit 0,0 ;and quit
TPS_OK:
MV_TPID TP_ID,TPS.TP_ID_TPS ;get the tp_id
RET ;and return
DO_TP_STARTED ENDP

DO_MC_ALLOCATE PROC
CALL CLEAR_VCB ;init the VCB to 00
MOV MAL.OPCODE_MAL,AP_M_ALLOCATE
;set verb opcode
MOV MAL.OPEXT_MAL,01 ;Mapped conversation
MV_TPID MAL.TP_ID_MAL,TP_ID ;set tp_id
MOV MAL.SYNC_LVL_MAL,AP_CONFIRM_SYNC_LEVEL
;confirm sync_level
MOV MAL.RTN_CTL_MAL,AP_WHEN_SESSION_ALLOCATED
;rtn ctrl when alloc
MOV MAL.SECURITY_MAL,AP_NONE ;no security

CLD
MOV CX,8
LEA SI,LUNAME2
LEA DI,MAL.PLU_ALIAS_MAL
REP MOVSB ;copy LUNAME2 to VCB

MOV CX,64 ;partners tp_name is 64 bytes
LEA SI,TP_NAME2 ;source is TP_NAME2
LEA DI,MAL.TP_NAME_MAL ;destination addr
REP MOVSB ;copy tp_name2 to VCB

MOV CX,8
LEA SI,MODENAME
LEA DI,MAL.MODE_NAME_MAL
REP MOVSB ;copy MODE_NAME to VCB

@APPC VCB ;issue MC_ALLOCATE verb
CMP MAL.PRIM_RC_MAL,WORD PTR AP_OK
;good MC_ALLOCATE ?
JE MAL_DONE
CALL SHOW_ERR ;if not, display the retcode
@DosExit 0,0 ;and just terminate
MAL_DONE:
MV_CVID CONV_ID,MAL.CONV_ID_MAL ;get the CONVERSATION_ID
RET
DO_MC_ALLOCATE ENDP

DO_RCV_AND_WAIT PROC
CALL CLEAR_VCB ;reset the VCB
MOV MRW.OPCODE_MRW,AP_M_RECEIVE_AND_WAIT
;set verb opcode
MOV MRW.OPEXT_MRW,BYTE PTR 01 ;Mapped converastion
MV_CVID MRW.CONV_ID_MRW,CONV_ID ;CONVERSATION_ID
MV_TPID MRW.TP_ID_MRW,TP_ID ;TP_ID
MOV MRW.MAX_LEN_MRW,4096 ;max length = 4096
MOV AX,WORD PTR ANB_PTR+2 ;get data pointer
MOV WORD PTR MRW.DPTR_MRW+2,AX ;set selector
MOV WORD PTR MRW.DPTR_MRW,0 ;offset = 0
@APPC VCB ;issue MC_RCV_AND_WAIT verb
MOV AX,MRW.DLEN_MRW ;get the length
MOV DATA_LEN,AX ;save it for DosWrite
RET ;return (no error ck)
DO_RCV_AND_WAIT ENDP

DO_TP_ENDED PROC
CALL CLEAR_VCB ;reset VCB to 00
MOV TPE.OPCODE_TPE,AP_TP_ENDED ;set opcode
MV_TPID TPE.TP_ID_TPE,TP_ID ;TP_ID
@APPC VCB ;issue TP_ENDED verb
CMP TPE.PRIM_RC_TPE,WORD PTR AP_OK
;check return code - is it good ?
JNE TPE_ERR1
RET ;if good, return
TPE_ERR1:
CALL SHOW_ERR ;display APPC error
MOV SYS_ERR,01 ;set error flag
@DosExit 0,0 ;and end the program
DO_TP_ENDED ENDP

SEND_FILENAME PROC
CALL CLEAR_VCB ;reset VCB to 0
MOV MSD.OPCODE_MSD,AP_M_SEND_DATA
;set verb opcode
MOV MSD.OPEXT_MSD,BYTE PTR 01 ;Mapped Conversation
MV_CVID MSD.CONV_ID_MSD,CONV_ID ;CONVERSATION_ID
MV_TPID MSD.TP_ID_MSD,TP_ID ;TP_ID
MOV MSD.DLEN_MSD,100 ;set data length
MOV WORD PTR MSD.DPTR_MSD,0 ;data addr offset = 0
MOV AX,WORD PTR ANB_PTR+2 ;get selector
MOV WORD PTR MSD.DPTR_MSD+2,AX ;set data address
@APPC VCB ;issue MC_SEND_DATA verb
CMP MSD.PRIM_RC_MSD,WORD PTR AP_OK
;check return code - is it good ?
JNE MSD_ERR1 ;if not, handle the error
MSD_EXIT:
RET ;return if ok
MSD_ERR1:
CMP MSD.PRIM_RC_MSD,WORD PTR AP_DEALLOC_ABEND
;DEALLOC_ABEND ?
JE MSD_EXIT ;if so, requestor quit
;(which is o.k.)
CALL SHOW_ERR ;else, display error
MOV SYS_ERR,01 ;and set error flag
@DosExit 0,0 ;and terminate
SEND_FILENAME ENDP

DO_MC_CONFIRMED PROC
CALL CLEAR_VCB ;reset VCB
MOV MCM.OPCODE_MCM,AP_M_CONFIRMED
;set verb opcode
MOV MCM.OPEXT_MCM,BYTE PTR 01 ;Mapped conversation
MV_CVID MCM.CONV_ID_MCM,CONV_ID ;CONVERSATION_ID
MV_TPID MCM.TP_ID_MCM,TP_ID ;TP_ID
@APPC VCB ;issue MC_CONFIRMED verb
CMP MCM.PRIM_RC_MCM,WORD PTR AP_OK
;check return code - is it good ?
JNE MCM_ERR1
RET ;return if ok
MCM_ERR1:
MOV SYS_ERR,01 ;set system err flag
CALL SHOW_ERR ;display error msg
@DosExit 0,0 ;and terminate
DO_MC_CONFIRMED ENDP


;============================================================================;
; ;
; OS/2 Call Related Subroutines ;
; ;
;============================================================================;


ALLOC_SHARED_BUFFER PROC

; APPC requires a shared unnamed segment to use as a data buffer

@DosAllocSeg 4096,ANB_PTR+2,1 ;4096 byte buff, 1=shared unnamed
CMP AX,0 ;check return code - is it good ?
JNE GSB_BAD ;if not, show an error
RET
GSB_BAD:
CALL SHOW_DOS_ERR ;display DOS err msg (rc in AX:)
@DosExit 0,0 ;and terminate the program
ALLOC_SHARED_BUFFER ENDP

OPEN_DOS_FILE PROC
MOV DOS_EOF,0 ;zero out the eof flag

; build the DosOpen directly (vs. using the supplied macro) since the data
; buffer with the filename is not in my data segment

@DEFINE DosOpen
PUSH WORD PTR FN_POINTER+2 ;push filename selector
PUSH WORD PTR FN_POINTER+0 ;push filename offset
@PUSHS FILEHANDLE ;push address of filehandle
@PUSHS ACTION ;push address of action flag
PUSH 0 ;push doubleword = 0 = filesize
PUSH 0
PUSH 0 ;push 0 = attrib
PUSH 0012H ;open_flag = 12 = open if no file,
PUSH 0022H ;mode = 22H
PUSH 0 ;push doubleword of 0s
PUSH 0
CALL FAR PTR DosOpen ;do a DosOpen

CMP AX,0 ;check return code - is it good ?
JNE BAD_OPEN ;if not, handle the error
MOV FILENAME_OK,0 ;Show we have a good filename
RET ;and return
BAD_OPEN:
CALL SHOW_DOS_ERR ;display the DOS error
MOV FILENAME_OK,0FFH ;Show a bad filename
RET ;and return
OPEN_DOS_FILE ENDP

CLOSE_DOS_FILE PROC
@DosClose FILEHANDLE ;go close the input file
CMP AX,0 ;check return code - is it good ?
JNE CDF_ERR1
RET
CDF_ERR1:
MOV SYS_ERR,01 ;set error flag
CALL SHOW_DOS_ERR ;display error msg.
@DosExit 0,0 ;and terminate
CLOSE_DOS_FILE ENDP

WRITE_DOSFILE PROC
CMP FIRST_FLAG,0 ;is this the first call to write ?
JNE WR_NOT_FIRST ;if so, we need to open thefile
MOV FIRST_FLAG,01 ;turn off the first time flag
CALL OPEN_DOS_FILE ;go open the output file
CMP FILENAME_OK,0 ;check return code - is it good ?
JE WR_NOT_FIRST ;if so, start writing it
MOV MSG_NO,13 ;'File Error - Unable to Open' msg
CALL SHOW_MSG ;show error message
@DosExit 0,0 ;and terminate
WR_NOT_FIRST:

; Directly build the DosWrite (vs. using the OS/2 macro) as the data is
; not in my dataseg

@define DosWrite
PUSH FILEHANDLE ;push filehandle
PUSH WORD PTR ANB_PTR+2 ;push buffer selector address
PUSH 0 ;push offset = 0
PUSH DATA_LEN ;push len.to wrt from RCV_AND_WAIT
PUSH DS ;push addr to return count to
PUSH OFFSET BYTES_OUT
CALL FAR PTR DosWrite ;go write data to the file

CMP AX,0 ;was the DosWrite ok ?
JNE WRITE_ERROR ;if not, handle the error

; Handle the progress message and cumulative transfer count.

MOV AX,BYTES_OUT ;get the count we just wrote
ADD COUNT_LO,AX ;add to the acculmulated count
ADC COUNT_HI,0 ;keep as a doubleword value

; Display it in hex

MOV AX,COUNT_HI ;get the high word of the count
LEA DI,COUNT_MSG ;address of display buffer
CALL CVHEX ;convert binary AX: to ASCII at DI
MOV AX,COUNT_LO ;get the low count
LEA DI,COUNT_MSG+4
CALL CVHEX ;convert to display fmt (in hex)
LEA SI,COUNT_MSG ;lets strip leading 0s
WR_STRIP_0:
CMP BYTE PTR [SI],'0' ;is it a zero ?
JNE WR_SHOWIT ;if not, display the value
MOV BYTE PTR [SI],' ' ;convert to leading blank
INC SI ;bump the index
CMP SI,OFFSET COUNT_MSG+7 ;are we done yet ?
JNE WR_STRIP_0
WR_SHOWIT:
MOV MSG_NO,7 ;progress message + count
CALL SHOW_MSG ;display the message

@VioWrtTTY COUNT_MSG,COUNT_MSGLEN,0
;display the count (in hex)
RET ;return with a good write
WRITE_ERROR:
CALL SHOW_DOS_ERR ;display DOS error msg
@DosExit 0,0 ;and terminate
WRITE_DOSFILE ENDP

;=============================================================================
REQUEST ENDP
CSEG ENDS
END REQUEST


  3 Responses to “Category : OS/2 Files
Archive   : OS2CMAPI.ZIP
Filename : FILEMREQ.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/